Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!uunet!mcsun!cernvax!chx400!bernina!neptune!inf.ethz.ch!brandis From: brandis@inf.ethz.ch (Marc Brandis) Newsgroups: comp.lang.modula2 Subject: Re: Nested routines as values? Message-ID: <22079@neptune.inf.ethz.ch> Date: 21 Jan 91 15:41:40 GMT References: <1991Jan19.151918.2734@waikato.ac.nz> Sender: news@neptune.inf.ethz.ch Reply-To: brandis@inf.ethz.ch (Marc Brandis) Organization: Departement Informatik, ETH, Zurich Lines: 57 In article <1991Jan19.151918.2734@waikato.ac.nz> ldo@waikato.ac.nz (Lawrence D'Oliveiro, Waikato University) writes: >I heard a rumour from a colleague that the Modula-2 standards people were >considering allowing routines declared within other routines to be >passed as values of PROCEDURE types. Can anybody tell me if this is true? > >I think it's a good idea, unless it means that PROCEDURE values become >descriptors, instead of straight addresses. If that's the case, it's >going to make it very cumbersome to interface to non-Modula-2 code. > As far as I know, there are only two ways to implement it. One is to assign a scope pointer together with the procedure address, which would mean making the procedure type a descriptor. The scope pointer would be the static link of the enclosing procedure. The other way is referred to in our institute as "global display". It is nothing but a global array with a field for each procedure including other procedures, in which the static link can be stored. References to outer scopes go through this global display. We had this implement in an experimental Oberon compiler, and as far as I know we were the first to do this. The first method has the disadvantage that procedure variables become larger and that they are no more compatible with other languages. Another disadvantage is that the scope pointer in the descriptor could possibly be used to access a stack frame that does no more exist. This could only be avoided when the language makes sure that the pointer is destroyed when the enclosing procedure terminates. One way to do this is not to allow the procedure to be assigned to a variable but only to be passed as a parameter. However, this would mean introducing a new type with very special rules just for this purpose. The second method has the advantage that the scope pointer used by all others can be reset at the end of the procedure. However, how well this construct would interface to other languages is an open question (I guess badly). Moreover, it does not work in the context of multitasking, as the global display would have to be shared among different tasks. Introducing a global display for each task would solve this problem, at the cost of another level of indirection and more complicated task management. But the biggest problem is that the construct has a very special semantics when recursion is used: The scope accessed is always the one at the topmost level, even if the procedure has been passed at a lower level. This can cause problems that are extremly hard to find. As a whole, I do not think that this is a really good idea. The only advantage of having the possibility to pass local procedures as procedure variables is to write generic broadcast procedures for data structures without having to use global variables. The variables of the enclosing procedure could be used instead. However, as exactly this feature has an unclear semantics and can improve performance only by a little bit (even depending on the machine architecture), I would say the best thing would to drop the idea as soon as possible. Marc-Michael Brandis Computer Systems Laboratory, ETH-Zentrum (Swiss Federal Institute of Technology) CH-8092 Zurich, Switzerland email: brandis@inf.ethz.ch