Block and Closure

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

Block and Closure

Andrey Larionov
What difference between this things. I know about Eliots post
describing closures in Squeak, but it's too massive and so special to
understand.
Thanks.

--
Andrey Larionov
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Block and Closure

K. K. Subramaniam
On Friday 10 April 2009 3:24:42 am Andrey Larionov wrote:
> What difference between this things. I know about Eliots post
> describing closures in Squeak, but it's too massive and so special to
> understand
Briefly,  A closure tracks the full computational state of its block.

A block is a executable entity with zero or more parameters. It may also use
variables from an outside scope. The parameters of the block are bound to the
arguments given when the block is evaluated. But what about variables like i
from an outer scope like in the example given by Bert a few weeks back :
          multiply := Array new: 4.
          1 to: 4 do: [:i |
              multiply at: i put: [:x | x * i].
          ].
          (multiply at: 3) value: 5.

When the block is evaluated, will it have the value it had at the time the
block was created or at the time it was evaluated? The behavior is
unspecified.  It is an open question :-).

In Squeak, i in the block will refer to the i in the do: block and the last
statement will print 25 because i would be 5 when do: terminates. A closure
maintains its own store for variables like i. At the time of creation, the
local store is initialized with i. At the time of invocation, i will refer to
this local copy, so the correct value of 15 will be printed.

HTH .. Subbu
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Block and Closure

Randal L. Schwartz
>>>>> "K" == K K Subramaniam <[hidden email]> writes:

K> In Squeak, i in the block will refer to the i in the do: block and the last
K> statement will print 25 because i would be 5 when do: terminates.

Not necessarily. I could see an implementation where i would be 4.

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Block and Closure

Bert Freudenberg
On 10.04.2009, at 05:48, Randal L. Schwartz wrote:

>>>>>> "K" == K K Subramaniam <[hidden email]> writes:
>
> K> In Squeak, i in the block will refer to the i in the do: block  
> and the last
> K> statement will print 25 because i would be 5 when do: terminates.
>
> Not necessarily. I could see an implementation where i would be 4.


And how exactly does that statement help a beginner to understand the  
distinction between a BlockContext and a BlockClosure? ;)

Andrey: Both are pretty much the same, there is no change in syntax.  
Closures simply are Blocks Done Right.

Try to run the example Subbu mentioned, and see if you would have  
expected the result or not. With closures it does what one would expect.

- Bert -


_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Block and Closure

Andrey Larionov
Thanks. I'l try to experiment with this example

On Fri, Apr 10, 2009 at 11:54, Bert Freudenberg <[hidden email]> wrote:

> On 10.04.2009, at 05:48, Randal L. Schwartz wrote:
>
>>>>>>> "K" == K K Subramaniam <[hidden email]> writes:
>>
>> K> In Squeak, i in the block will refer to the i in the do: block and the
>> last
>> K> statement will print 25 because i would be 5 when do: terminates.
>>
>> Not necessarily. I could see an implementation where i would be 4.
>
>
> And how exactly does that statement help a beginner to understand the
> distinction between a BlockContext and a BlockClosure? ;)
>
> Andrey: Both are pretty much the same, there is no change in syntax.
> Closures simply are Blocks Done Right.
>
> Try to run the example Subbu mentioned, and see if you would have expected
> the result or not. With closures it does what one would expect.
>
> - Bert -
>
>
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://lists.squeakfoundation.org/mailman/listinfo/beginners
>
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Block and Closure

Randal L. Schwartz
In reply to this post by Bert Freudenberg
>>>>> "Bert" == Bert Freudenberg <[hidden email]> writes:

>> Not necessarily. I could see an implementation where i would be 4.


Bert> And how exactly does that statement help a beginner to understand the
Bert> distinction between a BlockContext and a BlockClosure? ;)

It doesn't.  I was just pointing out a presumption about "the residual value
of things after they go out of scope" and/or "ways to implement a loop".

:-)

--
Randal L. Schwartz - Stonehenge Consulting Services, Inc. - +1 503 777 0095
<[hidden email]> <URL:http://www.stonehenge.com/merlyn/>
Smalltalk/Perl/Unix consulting, Technical writing, Comedy, etc. etc.
See http://methodsandmessages.vox.com/ for Smalltalk and Seaside discussion
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Block and Closure

Ralph Johnson
In the original Smalltalk, blocks were almost but not quite closures.
The ANSII standard says they are closures.  As far as I know, all the
Smalltalks except Squeak make blocks be closures.  So, changing the
way Squeak implements blocks will bring it into compliance with the
standard and more like other implementations of Smalltalk

I first ran into the problem of blocks not being closures when I tried
to write a program like

(1 to: 100) do: [:each | [self process: each] fork]

This will fork 100 processes.  If the first spawned process (the one
running [self process: 1]) starts to run right away, it will behave
like I expect.  But suppose the main thread creates all 100 processes
before it gives up control.  Then the value of "each" will be 100 and
so all 100 processes will execute [self process: 100], which is not at
all what I expect.  If blocks were closures then each execution of the
block would have its own context to store its argument, i.e. there
would be 100 versions of "each".

You can see a similar problem if you try to implement factorial the
way that Scheme programmers do it.

|factBlock|
factBlock := [:x | x <= 1 ifTrue: [1] ifFalse: [x * (factBlock value: x-1)]].
factBlock value: 100

Squeak complains that you are trying to evaluate a block recursively.
Most Smalltalk programmers would never try this, so they don't care
about Squeak's limitations.  But people coming to Squeak from a
functional programming language are annoyed, because they expect that
they can do this with blocks, but blocks are not complete closures.

-Ralph Johnson
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Block and Closure

Andrey Larionov
Thanks, all. Now I'm understood differences.

On Fri, Apr 10, 2009 at 20:09, Ralph Johnson <[hidden email]> wrote:

> In the original Smalltalk, blocks were almost but not quite closures.
> The ANSII standard says they are closures.  As far as I know, all the
> Smalltalks except Squeak make blocks be closures.  So, changing the
> way Squeak implements blocks will bring it into compliance with the
> standard and more like other implementations of Smalltalk
>
> I first ran into the problem of blocks not being closures when I tried
> to write a program like
>
> (1 to: 100) do: [:each | [self process: each] fork]
>
> This will fork 100 processes.  If the first spawned process (the one
> running [self process: 1]) starts to run right away, it will behave
> like I expect.  But suppose the main thread creates all 100 processes
> before it gives up control.  Then the value of "each" will be 100 and
> so all 100 processes will execute [self process: 100], which is not at
> all what I expect.  If blocks were closures then each execution of the
> block would have its own context to store its argument, i.e. there
> would be 100 versions of "each".
>
> You can see a similar problem if you try to implement factorial the
> way that Scheme programmers do it.
>
> |factBlock|
> factBlock := [:x | x <= 1 ifTrue: [1] ifFalse: [x * (factBlock value: x-1)]].
> factBlock value: 100
>
> Squeak complains that you are trying to evaluate a block recursively.
> Most Smalltalk programmers would never try this, so they don't care
> about Squeak's limitations.  But people coming to Squeak from a
> functional programming language are annoyed, because they expect that
> they can do this with blocks, but blocks are not complete closures.
>
> -Ralph Johnson
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://lists.squeakfoundation.org/mailman/listinfo/beginners
>
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Block and Closure

Lukas Renggli
In reply to this post by Ralph Johnson
> In the original Smalltalk, blocks were almost but not quite closures.
> The ANSII standard says they are closures.  As far as I know, all the
> Smalltalks except Squeak make blocks be closures.  So, changing the

I haven't yet met the Smalltalk implementation that has block closures
without obvious bugs. Making block closures correct and fast is not
trivial.

Lukas

--
Lukas Renggli
http://www.lukas-renggli.ch
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Block and Closure

Marcin Tustin
Why is this particularly hard for smalltalk? Scheme implementations
manage to do it. Is it simply that it's an afterthought, when it needs
to be designed in from the ground up?

On Fri, Apr 10, 2009 at 7:59 PM, Lukas Renggli <[hidden email]> wrote:

>> In the original Smalltalk, blocks were almost but not quite closures.
>> The ANSII standard says they are closures.  As far as I know, all the
>> Smalltalks except Squeak make blocks be closures.  So, changing the
>
> I haven't yet met the Smalltalk implementation that has block closures
> without obvious bugs. Making block closures correct and fast is not
> trivial.
>
> Lukas
>
> --
> Lukas Renggli
> http://www.lukas-renggli.ch
> _______________________________________________
> Beginners mailing list
> [hidden email]
> http://lists.squeakfoundation.org/mailman/listinfo/beginners
>
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Block and Closure

Lukas Renggli
> Why is this particularly hard for smalltalk? Scheme implementations
> manage to do it. Is it simply that it's an afterthought, when it needs
> to be designed in from the ground up?

Two common problems I observed are related to:

(1) Smalltalk inlines some blocks, such as the ones involved in
conditionals and loops. Even these loop blocks are no real blocks
anymore, they should behave exactly like real ones. For example the
following 2 expression should yield the same result #(1 2 3 4 5) when
evaluating the blocks in the collection:

     " in this case the block is inlined "
     1 to: 5 do: [ :index | collection add: [ index ] ]

     " in this case the block is not inlined "
     (1 to: 5) do: [ :index | collection add: [ index ] ]

(2) Some closure implementations perform invalid optimizations on
blocks and wrongly copy enclosed values when they think they are not
written to after block creation (AFAIK). In some cases this results in
very strange effects, such as that the following two expressions are
not symmetrical. In both cases the result should be #(5 5 5 5 5).

        | index |
        index := 0.
        [ index < 5 ] whileTrue: [
                collection add: [ index ].
                index := index + 1 ].

        | index |
        index := 0.
        [ index < 5 ] whileTrue: [
                index := index + 1.
                collection add: [ index ] ].

Cheers,
Lukas

--
Lukas Renggli
http://www.lukas-renggli.ch
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Block and Closure

K. K. Subramaniam
In reply to this post by Randal L. Schwartz
On Friday 10 April 2009 9:18:29 am Randal L. Schwartz wrote:
> In Squeak, i in the block will refer to the i in the do: block and the
> last statement will print 25 because i would be 5 when do: terminates.
>
> Not necessarily. I could see an implementation where i would be 4.
Possible. I just used Squeak 3.8/Etoys 4.0 as examples where i becomes 5 when
the iteration terminates.

Subbu
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Block and Closure

Markus Fritsche
In reply to this post by Lukas Renggli
Lukas Renggli <[hidden email]> wrote:

> Two common problems I observed are related to:

Interestingly, those problems do not arise if evaluated as a DoIt, but they
do come up in the Testcase in Pharo (latest patches from today).

I had three failing tests in ClosureTest, one test went green when I changed
& recompiled the method, two still failing.

Does the Compiler treat methods and DoIts differently (apparently, it does,
and I guess there are good reasons not to optimize simpe DoIts).

_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners
Reply | Threaded
Open this post in threaded view
|

Re: Re: Block and Closure

Lukas Renggli
> Does the Compiler treat methods and DoIts differently (apparently, it does,
> and I guess there are good reasons not to optimize simpe DoIts).

The compiler treats all code the same, however the semantics might be
different than what you would expect. For example workspace variables
share the semantics of global variables, thus they do not behave the
same way as temporary variables do when used with closures.

Lukas

--
Lukas Renggli
http://www.lukas-renggli.ch
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners