[Date Prev] [Date Next] [Thread Prev] [Thread Next] Date Index Thread Index Search archive:
Date:Mon May 25 19:35:00 2003 
Subject:Re: Scoped procedures 
From:A . Sloman 
Volume-ID:1030525.03 


Dave wrote
> I have a problem... take a look at this:
>
>   define a();
>     lvars i;
>
>     define b();
>       if i < 5 then
>         i + 1 -> i;
>         c();
>       endif;
>     enddefine;
>
>     define c();
>       b();
>     enddefine;
>
>     c();
>   enddefine;

did you notice that when you compile that you get a warning message
like this:

	;;; DECLARING VARIABLE c
	;;; IN FILE /home/staff/axs/mail/mail13
	;;; LINE 16929

Such warning messages should never be ignored. Many pop-11 programmers
get into the habit of thinking they can fix "declaring variable" warning
messages another day if the program seems to work, not realising that
that can cause trouble later on.

[Digression:
[At Birmingham the Ved command
	ENTER resetvars

I.e. ved_resetvars 'cancels' all automatically declared identifiers, so
that you can be sure that you will continue to get warning messages
about them. Use it after taking steps which you think deal with an
undeclared variable. The same thing may be undeclared in more than one
place.]]

In this case the trouble comes quickly.

When b is being compiled and the compiler comes across the undeclared
variable c, it declares a global variable, prints the warning, and
plants a CALL instruction to the hoped for procedure value of the global
variable.

Later c is defined as a nested procedure. By default the names of nested
procedures are now declared as lconstant (lexically scoped constant
identifiers).

So the c which is the procedure name has nothing to do
with the c that is the global variable.

If you had had a global variable whose value was a procedure you could
have had very obscure results!

As you surmise the answer is to use a forwad declaration, but it must be
of the right sort.

> Not difficult to see why, I guess... b() doesn't think c() has been
> declared. However, when I try to forward declare c() by changing the lvars
> line to:
>
>   lvars i, c;
>
> or:
>
>   lvars i;
>   lvars procedure c;
>
> as I _believe_ I should do (though I'm not sure), I get this:
>
>   ;;; MISHAP REDECLARING LEXICAL IDENTIFIER STATUS: c 0
>   ;;; (At or before line 11 column 15)

Because you first declare it as lvars then (implicitly) as lconstant.

You could override the lconstant default declaration of c, and declare
it as lvars procedure twice (or leave out procedure, which will can
cause a loss of efficiency if c is called in a loop.

  define a();
    lvars i, procedure c;

    define b();
      if i < 5 then
        i + 1 -> i;
        c();
      endif;
    enddefine;

    define lvars procedure c();
      b();
    enddefine;

    c();
  enddefine;

That will work apart from the fact that i is not initialised. You
may or may not get a run time mishap (from i < 5) depending on whether
lvars are initialised to 0 (as on suns) or not (as on alphas).[But
see below].

Alternatively, what you probably intend in this case, since you are not
going to assign different procedures to c, is lconstant:

  define a();
    lvars i;
	lconstant c;

    define b();
      if i < 5 then
        i + 1 -> i;
        c();
      endif;
    enddefine;

    define c();
      b();
    enddefine;

    c();
  enddefine;


> Creepy. Does anybody know how I can get around this, or should I just
> declare everything as globally scoped functions nad have done with it?

NEVER!

I suggest you pre-declare c as lconstant.

There is a further subtlety.

If you pre-declare and declare c as lvars (or as lvars procedure) then
on some systems the lexical variable i is initialised to 0.
So if you run a(); the '<' test gives no mishap.

However if you leave c as lconstant, then i is initialisd to
an anonymous undef object, which is better.
(See HELP UNDEF. REF IDENT/undef).

This means that running

	a();

produces this (or more messy version if popsyscall is true):

    ;;; MISHAP - NUMBER(S) NEEDED
    ;;; INVOLVING:  5 <undef>
    ;;; FILE     :  /home/staff/axs/asdfddd   LINE NUMBER:  22
    ;;; DOING    :  < b c a runproc


I don't know why the difference between making c lvars and making it
lconstant affects the initialisation of i;

You may be able to work it out by reading
	TEACH VARS_AND_LVARS

(originally written by David Young at Sussex and extended by me
here:

	http://www.cs.bham.ac.uk/research/poplog/teach/vars_and_lvars
)

and also
	HELP LEXICAL
	HELP DLOCAL
	REF VMCODE/'11.1  Lexical Scoping'
		(note what it says about type 1, type2, and type 3 identifiers.)

and maybe:
	REF PROCEDURE	

It may have something to do with the fact that if c is of type lvars,
then something can change c while A is running.

Maybe Steve Leach or Jonathan Cunningham can give an explanation...

I regard it as design flaw that you can't ask Pop-11 to initialise ALL
uninitialised lexical variables to an undef object. I can see why there
may be some efficiency gain if the machine architecture includes
instructions for setting up a procedure stack frame that clear local
variables, i.e. setting them to 0.

Very few languages have the kind of flexiblity and power that require
all the subtlety described in the documentation.

Aaron