Block semantics ....

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Block semantics ....

jamesl
Hi All,

I'm wondering about documentation to describe the block semantics of Pharo Smalltalk,
Specifically around the return context when a block contains a return:  [ ^ foo ]

Is a block valid only within the method that defined it and passed / called it?
I think it is, and when called outside of the context there is a BlockContext no longer exists error.

However, I'm looking for documentation or confirmation to ensure my testing was correct.

Rgs, James.
Reply | Threaded
Open this post in threaded view
|

Re: Block semantics ....

Eliot Miranda-2


On Sun, Nov 28, 2010 at 1:37 PM, James Ladd <[hidden email]> wrote:
Hi All,

I'm wondering about documentation to describe the block semantics of Pharo Smalltalk,
Specifically around the return context when a block contains a return:  [ ^ foo ]

Is a block valid only within the method that defined it and passed / called it?
I think it is, and when called outside of the context there is a BlockContext no longer exists error.

Note that BlockContext is no longer used.  | b | b := [thisContext class].  { b class. b value } answers { BlockClosure. MethodContext }.

The block is valid, but the attempt to return from a method can only be made once, whether made form an embedded block or the mehtod itself.  So the first attempt to retur wins.  However, a block =containing a return can still be evaluated.  An error will occur only if the retrn is actually executed.

So e.g.
    fibBlock
        | b |
        ^b := [:n| n < 0 ifTrue: [^self error: 'Nooooooo!'].  n < 2 ifTrue: [1] ifFalse: [(b value: n - 1) + (b value: n - 2)]]

    (0 to: 10) collect: self fibBlock

works fine but

     self fibBlock value: -1

will produce a cannot return error.


However, I'm looking for documentation or confirmation to ensure my testing was correct.

Rgs, James.

Reply | Threaded
Open this post in threaded view
|

Re: Block semantics ....

jamesl
In reply to this post by jamesl
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.

Does this appear most 'like' how blocks are handled in Pharo?

Rgs, James.


Reply | Threaded
Open this post in threaded view
|

Re: Block semantics ....

Eliot Miranda-2


On Mon, Nov 29, 2010 at 12:43 PM, James Ladd <[hidden email]> 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 is a good starting point for a general discussion of closures in programming languages.

HTH
Eliot

Rgs, James.



Reply | Threaded
Open this post in threaded view
|

Re: Block semantics ....

Stéphane Ducasse
In reply to this post by jamesl
James

I do not have the time but I have some slides on showing the difference between statically scoped lisp function and dynamically one.
This illustrates the funargs problem but probably you get access to that on wikipedia.
with block the object you refers from within a block may live longer than the method defining the block so you have to pay attention.

Stef

On Nov 29, 2010, at 9:43 PM, James Ladd 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.
>
> Does this appear most 'like' how blocks are handled in Pharo?
>
> Rgs, James.
>
>