[comp.lang.misc] Var scoping in Wirth-type languages

nevin1@ihlpf.ATT.COM (00704a-Liber) (03/10/88)

In article <2791@enea.se> sommar@enea.UUCP(Erland Sommarskog) writes:
>Nevin J Liber (nevin1@ihlpf.UUCP) writes:
>>How many novice Pascal programmers use many global vars because it saves
>>memory?  On a paging system, though, you may need more pages in real memory
>>because of the way the chaining of variables is done in Pascal.
>
>  Nevin would have loved them. They used a lot of global variables. 
>A typical procedure could have some local variables, but mostly they
>used the used the global ones, even for typical local purposes. To
>make it even more fun, all variables had one-letter prefixes like
>cnumber, cix etc. And on top of all, the modules were *huge*. 6000
>lines or so.
>
>So moral: You may save some execution time by having your variables
>global, but you since you are obscuring your code so fatally,
>you will lose the notion of what you are doing and introduce
>bugs and inefficiencies instead.

I would NOT have loved it!!  I hope that I didn't give the impression that
I like lots of global variables; that is not what I meant to do.  I happen
to think that the scoping rules are a plus for Pascal/Modula-2; but there
are other implementations that can be done when efficiency is necessary.
Globals, unless implemented with the optimization I'm going to state later,
are much less efficient than using locals!  If I didn't make that point
clear in my last posting, please excuse me.

For every level deep that a variable is used after it is declared, one
climb up the static chain of activation records (I think this is the right
term; it's been a long time since I took an implementation of PLs class) is
required to access the variable (this is due to the possibility of
recursion).  For example:

procedure p1();
var a1,b1:integer;

	procedure p2();
	var a2,b2:integer;

		procedure p3();
		var a3,b3:integer;
		begin
		...
		end

	begin
	...
	end

begin
...
end

I am defining proc p1() to be on level 1 and p2() on level 2 (making p3() a
level 3 declaration).  In order for p3() to access var a1, 2 climbs on the
static chain are required.  This is in contrast to p3() accessing a3, which
require no climbing of the static chain.

If some vars are declared 'globally' (at the topmost level), it is very
inefficient to access those variables in a procedure declared more than 1
or 2 levels deep.  There is a way to implement scoping that alleviates this
inefficiency, however.

In addition to the standard var declarations, one should be allowed to
declare a variable 'static' (to steal from C).  The scoping would be the
same as for standard vars (ex:  if var a2 in the above example were
declared as static, then only proc p2() and proc p3() could access it), but
it would always take up the same physical location in memory (it would not
be part of the activation record).  The only difference between a static
var and a standard var is that when used recursively, the same static var
is always manipulated (it would be like implicitly passing it as a 'var'
type).

Note:  This optimization can already be done on variables that can be
determined not to be used recursively and are referenced at a level deeper
then they are declared.  However, by adding explicit static declarations,
the programmer has much more flexibility.  Comments??
-- 
 _ __			NEVIN J. LIBER	..!ihnp4!ihlpf!nevin1	(312) 510-6194
' )  )				"The secret compartment of my ring I fill
 /  / _ , __o  ____		 with an Underdog super-energy pill."
/  (_</_\/ <__/ / <_	These are solely MY opinions, not AT&T's, blah blah blah

crowl@cs.rochester.edu (Lawrence Crowl) (03/11/88)

In article <3949@ihlpf.ATT.COM> nevin1@ihlpf.UUCP (00704a-Liber,N.J.) writes:
[access to variables outside the current scope]
>For every level deep that a variable is used after it is declared, one climb
>up the static chain of activation records is required to access the variable
>(this is due to the possibility of recursion).

An alternative technique for accessing these variables is "display registers".
Essentially, you have a register pointing to the current activation record for
each level of nesting.  No pointer chasing is required.  For more details, see
a compilers text.

In most modern architectures, access to local variables is no more expensive
than access to global variables.  For local variables, access is via a small
offset off the frame pointer (or one of the display registers).  For global
variables, access is via an absolute address.  Since absolute addresses require
more storage to encode, they often take more time to execute.

Even when global variables are more efficient, the gain in efficiency is often
not worth the loss in program clarity.
-- 
  Lawrence Crowl		716-275-9499	University of Rochester
		      crowl@cs.rochester.edu	Computer Science Department
...!{allegra,decvax,rutgers}!rochester!crowl	Rochester, New York,  14627

michael@boulder.Colorado.EDU (Michael Schmidt) (03/11/88)

Posting-Front-End: Gnews 1.1


In article <3949@ihlpf.ATT.COM>, nevin1@ihlpf (00704a-Liber) writes:
> If some vars are declared 'globally' (at the topmost level), it is very
> inefficient to access those variables in a procedure declared more than 1
> or 2 levels deep.  There is a way to implement scoping that alleviates this
> inefficiency, however.

I think the most UN*X compilers do it rather efficient. The
global variables are allocated in the bss (or data) segment. So
the access to global *and* local variables doesn't require to
follow the static chain.

	Michael Schmidt

ok@quintus.UUCP (Richard A. O'Keefe) (03/11/88)

In article <3949@ihlpf.ATT.COM>, nevin1@ihlpf (00704a-Liber) writes:
> If some vars are declared 'globally' (at the topmost level), it is very
> inefficient to access those variables in a procedure declared more than 1
> or 2 levels deep.  There is a way to implement scoping that alleviates this
> inefficiency, however.

Can you say "display"?  I knew you could.
You don't even need a full display.  Just retain a pointer to each level of
the display you actually need.  E.g.
	
program main(..); var x;
    procedure one(...); var y;
	procedure two(...); var z;
	    procedure three(...);
		begin {use x and y but not z}
		end;

-->
	    procedure three(...);
		var one_ptr: ^frame of one;
		begin
		    one_ptr := self^.parent^.parent;
		    {use global^.x and one_ptr^.y}
		end;

Any Pascal compiler which searches the static chain on every non-local
variable reference is a toy.

sommar@enea.se (Erland Sommarskog) (03/12/88)

00704a-Liber,N.J. (nevin1@ihlpf.UUCP) writes:
>Globals, unless implemented with the optimization I'm going to state later,
>are much less efficient than using locals!  If I didn't make that point
>clear in my last posting, please excuse me.
>
>For every level deep that a variable is used after it is declared, one
>climb up the static chain of activation records (I think this is the right

Nevin continues with an example, which I have deleted.

Yes, that kind of globals are slower, for sure. I was thinking of 
variables declared on module/program level. They are allocated to a 
fix adress, and there very quick to access. In the case I quoted, I 
think they were global on process level. I don't know the details of 
the implementation, but it seems likely that time to access a process 
variable and local variable are about the same.

>In addition to the standard var declarations, one should be allowed to
>declare a variable 'static' (to steal from C).  The scoping would be the
>...
>Note:  This optimization can already be done on variables that can be
>determined not to be used recursively and are referenced at a level deeper
>then they are declared.  However, by adding explicit static declarations,
>the programmer has much more flexibility.  Comments??

It seems to me that compiler should have the headache to decide which
variables should be static, not the programmer. 

-- 
Erland Sommarskog       
ENEA Data, Stockholm        
sommar@enea.UUCP           "Si tu crois l'amour tabou...
                            Regarde bien, les yeux d'un fou!!!" -- Ange

robison@uiucdcsb.cs.uiuc.edu (03/12/88)

For languages without "upward funargs" (e.g. Pascal), a global display
is sufficient, and furthermore requires only one extra push/pop per
procedure call. 

Let D[0..n] be the display registers.  Then the code for entering a procedure 
with lexical level n is:

	push D[n];
	D[n] := local_frame_pointer;

And the code for procedure exit is:

	pop D[n];
	return

One need not copy the entire display for each procedure call.
This was the Burroughs 6700's way of handling the display. I also notice 
that it was rediscovered in SIPLAN notices last year.  I suppose the
``expensive display'' myth is related to the ``expensive procedure call'' 
myth.  

I've heard that the "static link" approach is not inefficient with a
global optimizer.  The "chase" becomes a common subexpression and is
computed just once.

Arch D. Robison
University of Illinois at Urbana-Champaign
	
CSNET: robison@UIUC.CSNET
UUCP: {ihnp4,pur-ee,convex}!uiucdcs!robison
ARPA: robison@B.CS.UIUC.EDU (robison@UIUC.ARPA)

djs@actnyc.UUCP (Dave Seward) (03/13/88)

In article <3949@ihlpf.ATT.COM> nevin1@ihlpf.UUCP (00704a-Liber,N.J.) writes:
>Globals, unless implemented with the optimization I'm going to state later,
>are much less efficient than using locals!  If I didn't make that point
>clear in my last posting, please excuse me.
>
>For every level deep that a variable is used after it is declared, one
>climb up the static chain of activation records (I think this is the right
>term; it's been a long time since I took an implementation of PLs class) is
>required to access the variable
>...
>level 3 declaration).  In order for p3() to access var a1, 2 climbs on the
>static chain are required.  This is in contrast to p3() accessing a3, which
>require no climbing of the static chain.
>
>If some vars are declared 'globally' (at the topmost level), it is very
>inefficient to access those variables in a procedure declared more than 1
>or 2 levels deep.  There is a way to implement scoping that alleviates this
>inefficiency, however.
>
This is true in principle, but it doesn't have to be implemented this way.
First of all, a static link is a frame pointer for an enclosing activation
record and so is a constant for a given invocation of a nested routine. The
routine may therefore obtain the value once (through a static link chain
walkback, or however) and then reuse it any number of times, even across
calls. Some implementations create an array of static links, subscripted
by the lexical level, and pass it into a routine, so that only a single
dereference is required to access an outer level variable, regardless of
the number of intervening levels. Finally, I believe that most compilers
treat variables at the outermost level (usu. 1) as static anyway, so their
addresses are constants during the program's execution.

An optimizer can determine that a routine is not directly recursively called,
and can either place its variables in the enclosing scope, or can at least
access the enclosing scope variables directly via its own frame pointer,
rather than using the static link.

Dave Seward
uucp.actnyc.djs

gvcormack@watdragon.waterloo.edu (Gordon V. Cormack) (03/14/88)

In article <170500016@uiucdcsb>, robison@uiucdcsb.cs.uiuc.edu writes:
> 
> For languages without "upward funargs" (e.g. Pascal), a global display
> is sufficient, and furthermore requires only one extra push/pop per
> procedure call. 

Not true.  Procedure and Function parameters can access an environment
totally disjoint from the calling environment.  Hence, each such 
parameter requires its own display (or static link). 
-- 
Gordon V. Cormack     CS Dept, University of Waterloo, Canada N2L 3G1
                      gvcormack@waterloo  { .CSNET or .CDN or .EDU }
                      gvcormack@water         { UUCP or BITNET }

michael@boulder.Colorado.EDU (Michael Schmidt) (03/14/88)

Posting-Front-End: Gnews 1.1


In article <170500016@uiucdcsb>, robison@uiucdcsb writes:
>
>For languages without "upward funargs" (e.g. Pascal), ...

What do you mean with "upward funargs"? And (e.g. Pascal)??

	Michael Schmidt

michael@boulder.Colorado.EDU (Michael Schmidt) (03/14/88)

Posting-Front-End: Gnews 1.1


In article <170500016@uiucdcsb>, robison@uiucdcsb writes:
>For languages without "upward funargs" (e.g. Pascal), a global display
>is sufficient, and furthermore requires only one extra push/pop per
>procedure call. 

No! Cosider the following program:

{ LAST EDIT: Sat Mar 12 12:27:35 MST 1988 by Michael Schmidt (michael) }
PROGRAM funparm (input, output);
VAR FirstTime : Boolean;
PROCEDURE f(procedure x);
VAR j: integer;
    BEGIN x END; {f}

PROCEDURE g();
VAR i: integer;
    PROCEDURE h();
    	BEGIN
	    if FirstTime then begin
	    	FirstTime := false;
		f(h)
    	    end else
	    	writeln(i)
	END; {h}

    BEGIN h END; {g}

BEGIN
    
END. {funparm}

At execution of 'h', you will have the frame of 'f' in the display
for level 1 instead of the frame of 'g'! And you will get the
value of 'j' instead of the value of 'i'! Right?

	Michael

firth@sei.cmu.edu (Robert Firth) (03/14/88)

In article <170500016@uiucdcsb> robison@uiucdcsb.cs.uiuc.edu writes:
>
>For languages without "upward funargs" (e.g. Pascal), a global display
>is sufficient, and furthermore requires only one extra push/pop per
>procedure call. 

Sigh!  The erroneous display implementations seem to be
repeatedly rediscovered.  One more time: this fails in
a language with any one of

	parametric procedures
	procedure variables
	parametric labels
	label variables
	jumps out of procedures

It therefore fails in ISO Pascal, under the fifth case.

nevin1@ihlpf.ATT.COM (00704a-Liber) (03/19/88)

In article <2832@enea.se> sommar@enea.UUCP(Erland Sommarskog) writes:
.00704a-Liber,N.J. (nevin1@ihlpf.UUCP) writes:
.
..In addition to the standard var declarations, one should be allowed to
..declare a variable 'static' (to steal from C).  The scoping would be the
.....
..Note:  This optimization can already be done on variables that can be
..determined not to be used recursively and are referenced at a level deeper
..then they are declared.  However, by adding explicit static declarations,
..the programmer has much more flexibility.  Comments??
.
.It seems to me that compiler should have the headache to decide which
.variables should be static, not the programmer. 

I did not propose to eliminate that 'headache' from the compiler (see the
word 'addition' in my first sentence) but to allow the user to specify
variables he wishes to use on more than one level but allows recursive
calls to use the same variable.  With a type 'static', he can declare
global-type (quick-access) variables AND restrict their scope.  This would
be in *addition* to the standard types of variable declarations.
-- 
 _ __			NEVIN J. LIBER	..!ihnp4!ihlpf!nevin1	(312) 510-6194
' )  )				"The secret compartment of my ring I fill
 /  / _ , __o  ____		 with an Underdog super-energy pill."
/  (_</_\/ <__/ / <_	These are solely MY opinions, not AT&T's, blah blah blah