On Mon, Nov 29, 2010 at 12:43 PM, James Ladd <[email protected]> wrote:
> Hi Eliot, > > I was suspecting you might respond, you really know your stuff. > > I think I'm more confused now that before but in a good way. > I have more information thank to you. > > My need to fully understand blocks is to implement them in Redline. > > Maybe it will be sufficient to 'limit' the use of a block with a > return to the method in which is was defined? > ie: Method A can define the block and send it as an argument, but once > method A has been exited, the block is no longer valid, at least not > the return part. > > Right. That's what one gets with nested functions in Pascal. One cannot return a nested function in Pascal because a nested function's lexical bindings are only valid within the enclosing activation. This allows the implementation to refer to its lexical bindings by reference, either with a "static chain" or a "display". The static chain is the common implementation technique now. The head of the static chain is a copy of the frame pointer of the next lexically-enclosing function, stored in the nested function and its activation. Any lexical binding can be reached by following the static chain. An alternative technique is a "display", which is essentially an array of frame pointers, one for each level of nesting, allowing implementing lexical binding access by a double indirection. But these are only "downward funargs" because they can only be passed down the stack. Smalltalk (and many other languages) provides "full upward funargs" becaue they can outlive their enclosing activation and be returned. > > Does this appear most 'like' how blocks are handled in Pharo? > > Sort of. The main difference is that in Smalltalks derived from Smalltalk-80 activation records are first-class objects and so can outlive their invocation. i.e. a Smalltalk activation is an object, /not/ space on a stack. Under the covers the VM /may/ choose to implement activations in a stack-like manner, lazily creating objects only when needed (which is what Cog and VisualWorks do), but that's a hidden optimization and conceptually creating an activation creates an object. So there is no conceptual problem having a block refer to its enclosing activation after that activation has returned, but obviously the attempt to return a second time must fail because the place to return to is already in use, or has already been returned from. However, apart from return, there is no need to refer to the outer activation to access lexical bindings. The scheme is to copy the values of lexical bindings that can't change while executing a block that refers to them (e.g. arguments and temps assigned to before a block is created but not afterwards), and move the lexical bindings that can change off teh stack into a heap-allocated Array. You can read about this in excruciating detail on my blog in http://www.mirandabanda.org/cogblog/2008/06/07/closures-part-i/, http://www.mirandabanda.org/cogblog/2008/07/22/closures-part-ii-the-bytecodes/and http://www.mirandabanda.org/cogblog/2008/07/24/closures-part-iii-the-compiler/ . BTW, the Wikipedia page on the Funarg problem<http://en.wikipedia.org/wiki/Funarg_problem>is a good starting point for a general discussion of closures in programming languages. HTH Eliot > > Rgs, James. > > >
