Path: utzoo!attcan!uunet!parcplace!deutsch From: deutsch@parcplace.com (Peter Deutsch) Newsgroups: comp.object Subject: Re: code blocks (aka closures) Message-ID: Date: 2 Jul 90 22:00:16 GMT References: <12396@june.cs.washington.edu> <1112@carol.fwi.uva.nl> <5305@stpstn.UUCP> <11002@alice.UUCP> Sender: news@parcplace.com Organization: ParcPlace Systems, Mountain View, CA Lines: 34 In-reply-to: ark@alice.UUCP's message of 1 Jul 90 17:31:19 GMT Andrew Koenig's post did a nice job of demonstrating the value and power of closures. However, I find I disagree with his analysis of why they are not appropriate for C or C++. C and C++ already take the point of view that one can create, and freely pass around, pointers to locally allocated variables, despite the fact that these pointers become invalid when one leaves the dynamic scope in which the variable was allocated. Adding closures would not create qualitatively new problems of this kind: they would simply be another case of an existing problem. If the former problem isn't sufficient to motivate a requirement for a garbage collector, I don't think the latter is either. Closures can be implemented with absolutely no overhead for places that don't use them, and relatively low overhead for places that DO use them. I think the trick I'm about to describe was originally invented at Xerox PARC; at least, that's where I remember first hearing it. The representation of a closure is a pointer to a small block of code stored in the enclosing stack frame. This code pushes an extra argument -- the address of the frame itself -- and then jumps to the actual procedure. The inner procedure thus takes an additional implicit argument, which is the address of the correct dynamic instance of the statically enclosing frame. This can obviously be iterated to handle multiple levels of inner procedure. It requires a small amount of cooperation from the operating system and/or the machine architecture, since it requires the ability to construct code on the fly and hence the ability to properly synchronize the instruction and data caches. Using this scheme, a call through a procedure variable is always simply an indirect call. Procedure variables still only occupy the same amount of space as any other kind of pointer. Objectworks for Smalltalk-80 happens not to implement closures this way, because its fundamental operation is method invocation, not procedure call. However, I can imagine using a scheme (:-)) like this for Lisp.