Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!ucbvax!DMSWWU1A.BITNET!ONM64 From: ONM64@DMSWWU1A.BITNET (Kai Henningsen) Newsgroups: comp.lang.modula2 Subject: Re: procedure variables (ca. 80 lines) Message-ID: Date: 25 Apr 89 18:06:28 GMT Sender: daemon@ucbvax.BERKELEY.EDU Reply-To: Modula2 List Organization: The Internet Lines: 71 X-Unparsable-Date: Tue, 25 Apr 89 14:07:05 MES Well, my friendly Pascal Compiler (Turbo Pascal 5.0) does this in exactly the same way as Wirth defines it for Modula-2, so it has to be doable ... The reasons behind the various do's and dont's are as follows: 1. Why not allow "standard procedures"? Simple: the compiler writer may decide to implement these not like ordinary procedures, but in some special way. Thus, they have no address that could be stored in a procedure variable. For example, try to imagine the following: v: PROCEDURE (ARRAY OF CHAR) : CARDINAL; v := SIZE; Somewhat problematic ... 2. Why not allow local procedures? Simple: because it's NOT simple :-) Really: This is part of ISO Pascal. Up to now, I have seen one implementation, in Mac MPW Pascal. I looked at the code. Now I know why you don't want to implement it ... It's like this: If you have a local Procedure, then you obviously have to save the static calling chain. Most Compilers do this by passing, as an invisible parameter, a pointer to the procedure's parent's stack frame. In the case of a procedure variable, that means you have to put this pointer in the variable, too. BUT a global procedure does not expect to get this parameter! So, you end up generating code like this: IF procvar.stackframe#NIL THEN push(procvar.stackframe) END; call(procvar.adr); Yechhh!! By the way, we have another problem here. Suppose the following: VAR v: PROCEDURE; PROCEDURE A; PROCEDURE B; BEGIN END B; BEGIN v:=B; END A; BEGIN A; v(); END; Where's my stackframe gone to??? There are two approaches to this problem: First, ISO Pascal. We do not allow procedure variables, except as parameters. Obviously, the stack frame will thus be there. Second, Lisp. The stack frame is an (invisible) Lisp object. As long as there exists a procedure variable pointing to X, the garbage collector will not kill the stack frame for that invocation of X's parent. Obviously, stack frames are heap objects chained with pointers. Nice but SLOWWWW. Of course, there is always a third way: don't allow this. Modula-2. 3. Now what about non-exported global procedures? Well, what about it? Non-exported procedures are exactly like exported ones, except the module importer does not know these by name. Since he does not know the name of any procedure called via a procedure variable either, that shouldn't hurt. Of course, the implementor may choose to optimize those procedures on the grounds that they will only be used from places known in advance. So does Turbo Pascal 5.0. But, if they are used with procedure variables at all (wether exported or not), this must break down. What do we do? Either, we restrict optimizing in cases where a procedure is exported or assigned to a procedure variable, or we allow the user to decide on optimizations (remember compiler directives?), but allow export & assignment only on non-optimized procedures. (TP5 really does a mix of the two.) Kai onm64 @ dmswwu1a . bitnet