Modify block (closure) parameters

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

Modify block (closure) parameters

psea
Hi Smalltalkers!

Here is a question I can't find answer with google.
In short: Does block parameters and block local variables are the same thing (semantically) inside closure? It looks like it's not. Below the explanation.

===================
Here is the accumulator function (first attempt):

makeAcc := [ :acc |  
        [:n | acc:=acc+n. acc]]

It turns out it doesn't work as intended:

a1 := makeAcc value: 10
a1 value: 1 => 11
a1 value: 1 => 11
a1 value: 2 => 12

====================
Here is the second attempt:

makeAcc := [ :acc |  
        | total |
        total:=acc.
        [:n | total:=total+n. total]]

And it does work as intended:

a1 := makeAcc value: 10
a1 value: 1 => 11
a1 value: 1 => 12
a1 value: 2 => 14

So if we use the local variable to store accumulator it works as it should and remembers the value between function (block) calls. But if we use block parameter to store the value of accumulator it does not remembers the value between calls.
Why is it so?
 
P.S. Sorry for my English. I do all my best.
Reply | Threaded
Open this post in threaded view
|

Re: Modify block (closure) parameters

Casey Ransberger-2
There's a preference (I can't recall the name but it's something like "allow block argument assignment"; I'll try to find it for you when I get back to the computer. Anyhow enabling this preference is there for backwards compatibility with old code that assigns to block args.

If you're writing new code, it's best to just disable the preference. This way an error will be signaled when attempting to assign to block arguments, such that you'll start getting used to working around this "limitation."

Closures give you a lot, and you won't ever truly *need* to modify a block arg. There's always another way to do it.

I won't try to go to deep into closure semantics, but if you do feel you'd like to take a deeper dive on the subject, the best explanation of it I've read (which -- perhaps sadly -- doesn't use the term "closure" at all) is in chapter 3.2 of Structure and Interpretation of Computer Programs.

The bad news is, that book was written about a language that's a bit off topic here (Scheme, the language closures were invented for.)

The good news is, if you want to read it, the whole book is online. Here's a link to the chapter I mentioned:

<a href="http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-21.html#%_sec_3.2">http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-21.html#%_sec_3.2

Hope this helps!

Casey

On Aug 5, 2013, at 1:44 AM, psea <[hidden email]> wrote:

> Hi Smalltalkers!
>
> Here is a question I can't find answer with google.
> In short: Does block parameters and block local variables are the same thing
> (semantically) inside closure? It looks like it's not. Below the
> explanation.
>
> ===================
> Here is the accumulator function (first attempt):
>
> makeAcc := [ :acc |  
>        [:n | acc:=acc+n. acc]]
>
> It turns out it doesn't work as intended:
>
> a1 := makeAcc value: 10
> a1 value: 1 => 11
> a1 value: 1 => 11
> a1 value: 2 => 12
>
> ====================
> Here is the second attempt:
>
> makeAcc := [ :acc |  
>        | total |
>        total:=acc.
>        [:n | total:=total+n. total]]
>
> And it does work as intended:
>
> a1 := makeAcc value: 10
> a1 value: 1 => 11
> a1 value: 1 => 12
> a1 value: 2 => 14
>
> So if we use the local variable to store accumulator it works as it should
> and remembers the value between function (block) calls. But if we use block
> parameter to store the value of accumulator it does not remembers the value
> between calls.
> Why is it so?
>
> P.S. Sorry for my English. I do all my best.
>
>
>
> --
> View this message in context: http://forum.world.st/Modify-block-closure-parameters-tp4702118.html
> Sent from the Squeak - Beginners mailing list archive at Nabble.com.
> _______________________________________________
> 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: Modify block (closure) parameters

psea
Hi, Casey

It'll be great if you can tell the name of the parameter.

The assignment to block argument does actually work with no error. So it looks like "allow block argument assignment" parameter is enabled. Here is the example:

[:x | x := x + 1. x] value: 1  => 2

But as we can see from examples in the previous post it behaves in a strange way.

Oh yes, SICP it's a great book. I've read it with great pleasure. And actually it's thats why I try to understand better the semantics of block's arguments. Because in functional programming (and scheme also) the function's arguments and local variables are actually the same things. (local variables is just syntactic sugar for function arguments). Here is a one-to-one mapping in scheme for examples in previous post and they behaves equally (as expected).

=======================
version with assignment to function argument

(define (make-acc acc)
    (lambda (n)
        (begin
            (set! acc (+ acc n))
            acc)))

(define a1 (make-acc 10))

(a1 1) => 11
(a1 1) => 12
(a1 2) => 14

======================
version with assignment to local variable

(define (make-acc acc)
    (let ((define total acc))
        (lambda (x)
            (begin
                (set! total (+ total x))
                total))))

(define a1 (make-acc 10))

(a1 1) => 11
(a1 1) => 12
(a1 2) => 14

Some clarification: I'm not going to program in functional style with Smalltalk. The plan is to fully utilize the  OOP in learning purposes. That's why I dive into ST :-). I'm just trying to understand the semantics of constructs in the language. In either case there are functional tools in ST (methods in Collections inject:to: collect: etc.) and blocks are essential part of it. Therefore it's good to understand semantics of block.

Addition: I've saw somewhere in the net the term "Closure compiler" for Squeak. Maybee it can be the key to understanding the problem. But have no time to dive into.
Reply | Threaded
Open this post in threaded view
|

Re: Modify block (closure) parameters

Casey Ransberger-2
In reply to this post by psea
I didn't read your post clearly enough. Yep, that would seem odd. You may have a bug there. I'm not sure why that happens. It looks like the outer context isn't taking the assignment, but hanging onto the initial value it receives from #value:. 

I'm not totally sure we should expect to be able to do what you're trying to do in modern Squeak. I haven't assigned to a block arg in a long time (I keep allow block assignments off unless I'm loading old code.) I don't know what the status is there. I run a relatively recent Cog VM on a 10.7.5 Mac and I'm seeing the same behavior in Squeak 4.4.

When I switch to an old VM (3.8.18Beta3U) and run Squeak 3.0, your snippet works as expected. I'm not sure if this is in the image or the VM yet, or whether it's expected behavior or not with allowBlockArgumentAssignment (Again, I usually turn it off.)

The main take away here is, don't do that:) as it's a back-compat feature and it really ought to have a big sign on it that says DEPRECATED. If you're trying to load some older code and running into this, it might be better to actually rewrite it not to assign to block arguments in my opinion (and maybe I'm nuts.)

Can you tell me what VM you're using?

Smalltalk vmVersion "this will tell us"

And also which version of Squeak?

SmalltalkImage current systemInformationString "ditto"

Also, what's the OS of the host system?



On Mon, Aug 5, 2013 at 1:44 AM, psea <[hidden email]> wrote:
Hi Smalltalkers!

Here is a question I can't find answer with google.
In short: Does block parameters and block local variables are the same thing
(semantically) inside closure? It looks like it's not. Below the
explanation.

===================
Here is the accumulator function (first attempt):

makeAcc := [ :acc |
        [:n | acc:=acc+n. acc]]

It turns out it doesn't work as intended:

a1 := makeAcc value: 10
a1 value: 1 => 11
a1 value: 1 => 11
a1 value: 2 => 12

====================
Here is the second attempt:

makeAcc := [ :acc |
        | total |
        total:=acc.
        [:n | total:=total+n. total]]

And it does work as intended:

a1 := makeAcc value: 10
a1 value: 1 => 11
a1 value: 1 => 12
a1 value: 2 => 14

So if we use the local variable to store accumulator it works as it should
and remembers the value between function (block) calls. But if we use block
parameter to store the value of accumulator it does not remembers the value
between calls.
Why is it so?

P.S. Sorry for my English. I do all my best.



--
View this message in context: http://forum.world.st/Modify-block-closure-parameters-tp4702118.html
Sent from the Squeak - Beginners mailing list archive at Nabble.com.
_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners



--
Casey Ransberger

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

Modify block (closure) parameters

Louis LaBrunda
Hi Guys,

FWIW, VA Smalltalk doesn't allow changing block arguments.

Lou

On Tue, 6 Aug 2013 13:42:33 -0700, Casey Ransberger
<[hidden email]> wrote:

>I didn't read your post clearly enough. Yep, that would seem odd. You may
>have a bug there. I'm not sure why that happens. It looks like the outer
>context isn't taking the assignment, but hanging onto the initial value it
>receives from #value:.
>
>I'm not totally sure we should expect to be able to do what you're trying
>to do in modern Squeak. I haven't assigned to a block arg in a long time (I
>keep allow block assignments off unless I'm loading old code.) I don't know
>what the status is there. I run a relatively recent Cog VM on a 10.7.5 Mac
>and I'm seeing the same behavior in Squeak 4.4.
>
>When I switch to an old VM (3.8.18Beta3U) and run Squeak 3.0, your snippet
>works as expected. I'm not sure if this is in the image or the VM yet, or
>whether it's expected behavior or not with allowBlockArgumentAssignment
>(Again, I usually turn it off.)
>
>The main take away here is, don't do that:) as it's a back-compat feature
>and it really ought to have a big sign on it that says DEPRECATED. If
>you're trying to load some older code and running into this, it might be
>better to actually rewrite it not to assign to block arguments in my
>opinion (and maybe I'm nuts.)
>
>Can you tell me what VM you're using?
>
>Smalltalk vmVersion "this will tell us"
>
>And also which version of Squeak?
>
>SmalltalkImage current systemInformationString "ditto"
>
>Also, what's the OS of the host system?
>
>
>
>On Mon, Aug 5, 2013 at 1:44 AM, psea <[hidden email]> wrote:
>
>> Hi Smalltalkers!
>>
>> Here is a question I can't find answer with google.
>> In short: Does block parameters and block local variables are the same
>> thing
>> (semantically) inside closure? It looks like it's not. Below the
>> explanation.
>>
>> ===================
>> Here is the accumulator function (first attempt):
>>
>> makeAcc := [ :acc |
>>         [:n | acc:=acc+n. acc]]
>>
>> It turns out it doesn't work as intended:
>>
>> a1 := makeAcc value: 10
>> a1 value: 1 => 11
>> a1 value: 1 => 11
>> a1 value: 2 => 12
>>
>> ====================
>> Here is the second attempt:
>>
>> makeAcc := [ :acc |
>>         | total |
>>         total:=acc.
>>         [:n | total:=total+n. total]]
>>
>> And it does work as intended:
>>
>> a1 := makeAcc value: 10
>> a1 value: 1 => 11
>> a1 value: 1 => 12
>> a1 value: 2 => 14
>>
>> So if we use the local variable to store accumulator it works as it should
>> and remembers the value between function (block) calls. But if we use block
>> parameter to store the value of accumulator it does not remembers the value
>> between calls.
>> Why is it so?
>>
>> P.S. Sorry for my English. I do all my best.
>>
>>
>>
>> --
>> View this message in context:
>> http://forum.world.st/Modify-block-closure-parameters-tp4702118.html
>> Sent from the Squeak - Beginners mailing list archive at Nabble.com.
>> _______________________________________________
>> Beginners mailing list
>> [hidden email]
>> http://lists.squeakfoundation.org/mailman/listinfo/beginners
>>
-----------------------------------------------------------
Louis LaBrunda
Keystone Software Corp.
SkypeMe callto://PhotonDemon
mailto:[hidden email] http://www.Keystone-Software.com

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

Re: Modify block (closure) parameters

Casey Ransberger-2


On Tue, Aug 6, 2013 at 2:14 PM, Louis LaBrunda <[hidden email]> wrote:
Hi Guys,

FWIW, VA Smalltalk doesn't allow changing block arguments.

Lou

On Tue, 6 Aug 2013 13:42:33 -0700, Casey Ransberger
<[hidden email]> wrote:

>I didn't read your post clearly enough. Yep, that would seem odd. You may
>have a bug there. I'm not sure why that happens. It looks like the outer
>context isn't taking the assignment, but hanging onto the initial value it
>receives from #value:.
>
>I'm not totally sure we should expect to be able to do what you're trying
>to do in modern Squeak. I haven't assigned to a block arg in a long time (I
>keep allow block assignments off unless I'm loading old code.) I don't know
>what the status is there. I run a relatively recent Cog VM on a 10.7.5 Mac
>and I'm seeing the same behavior in Squeak 4.4.
>
>When I switch to an old VM (3.8.18Beta3U) and run Squeak 3.0, your snippet
>works as expected. I'm not sure if this is in the image or the VM yet, or
>whether it's expected behavior or not with allowBlockArgumentAssignment
>(Again, I usually turn it off.)
>
>The main take away here is, don't do that:) as it's a back-compat feature
>and it really ought to have a big sign on it that says DEPRECATED. If
>you're trying to load some older code and running into this, it might be
>better to actually rewrite it not to assign to block arguments in my
>opinion (and maybe I'm nuts.)
>
>Can you tell me what VM you're using?
>
>Smalltalk vmVersion "this will tell us"
>
>And also which version of Squeak?
>
>SmalltalkImage current systemInformationString "ditto"
>
>Also, what's the OS of the host system?
>
>
>
>On Mon, Aug 5, 2013 at 1:44 AM, psea <[hidden email]> wrote:
>
>> Hi Smalltalkers!
>>
>> Here is a question I can't find answer with google.
>> In short: Does block parameters and block local variables are the same
>> thing
>> (semantically) inside closure? It looks like it's not. Below the
>> explanation.
>>
>> ===================
>> Here is the accumulator function (first attempt):
>>
>> makeAcc := [ :acc |
>>         [:n | acc:=acc+n. acc]]
>>
>> It turns out it doesn't work as intended:
>>
>> a1 := makeAcc value: 10
>> a1 value: 1 => 11
>> a1 value: 1 => 11
>> a1 value: 2 => 12
>>
>> ====================
>> Here is the second attempt:
>>
>> makeAcc := [ :acc |
>>         | total |
>>         total:=acc.
>>         [:n | total:=total+n. total]]
>>
>> And it does work as intended:
>>
>> a1 := makeAcc value: 10
>> a1 value: 1 => 11
>> a1 value: 1 => 12
>> a1 value: 2 => 14
>>
>> So if we use the local variable to store accumulator it works as it should
>> and remembers the value between function (block) calls. But if we use block
>> parameter to store the value of accumulator it does not remembers the value
>> between calls.
>> Why is it so?
>>
>> P.S. Sorry for my English. I do all my best.
>>
>>
>>
>> --
>> View this message in context:
>> http://forum.world.st/Modify-block-closure-parameters-tp4702118.html
>> Sent from the Squeak - Beginners mailing list archive at Nabble.com.
>> _______________________________________________
>> Beginners mailing list
>> [hidden email]
>> http://lists.squeakfoundation.org/mailman/listinfo/beginners
>>
-----------------------------------------------------------
Louis LaBrunda
Keystone Software Corp.
SkypeMe callto://PhotonDemon
mailto:[hidden email] http://www.Keystone-Software.com

_______________________________________________
Beginners mailing list
[hidden email]
http://lists.squeakfoundation.org/mailman/listinfo/beginners



--
Casey Ransberger

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

Re: Modify block (closure) parameters

psea
In reply to this post by Casey Ransberger-2
Ok, i've got it. So in ST it's just not allowed assign to a block argument for some reason. Let's consider it a language feature. And it's ok, different language - different rules. Thanks for pointing me on that!
Now, I've turn off allowBlockArgumentAssignment property.

What's worried me is that in other languages I'm familiar with it's a normal thing to assign to a function argument (Scheme, C, Python, JavaScript).

answer to your questions:
Smalltalk vmVersion 'Squeak3.10.2 of 11 February 2010 [latest update: #9314]'
SmalltalkImage current systemInformationString "ditto" 'Squeak4.3
latest update: #11860
Current Change Set: Unnamed1'
Windows XP.

PS But you should agree with me that

makeAcc := [ :acc |
        [:n | acc:=acc+n. acc]]

looks a little bit better and concise than

makeAcc := [ :acc |
        | total |
        total:=acc.
        [:n | total:=total+n. total]]

:-)

And thanks for the links.
Reply | Threaded
Open this post in threaded view
|

Re: Modify block (closure) parameters

Levente Uzonyi-2
On Wed, 7 Aug 2013, psea wrote:

> Ok, i've got it. So in ST it's just not allowed assign to a block argument
> for some reason. Let's consider it a language feature. And it's ok,

It's a compiler bug. The compiler doesn't handle this case.
- TempVariableNode >> #analyseClosure: returns if the receiver is a block
argument without checking the preference.
- BlockNode >> #postNumberingProcessTempsWithin:rootNode: only checks the
temporaries, but not the arguments of the receiver.
- Even if the above two are fixed, the temp index is still out of bounds,
because removing arguments is not supported (see
#removeTempNode:ifAbsent: and its sender), so the original temp for the
argument will be kept.

> different language - different rules. Thanks for pointing me on that!
> Now, I've turn off allowBlockArgumentAssignment property.
>
> What's worried me is that in other languages I'm familiar with it's a normal
> thing to assign to a function argument (Scheme, C, Python, JavaScript).

Storing into a block or method argument is considered bad practice.
Support for it is/was planned to be removed. Even though it can yield
somewhat better performance, it's something you'll rarely see in
Smalltalk code.

>
> answer to your questions:
> Smalltalk vmVersion 'Squeak3.10.2 of 11 February 2010 [latest update:
> #9314]'
> SmalltalkImage current systemInformationString "ditto" 'Squeak4.3
> latest update: #11860
> Current Change Set: Unnamed1'
> Windows XP.
>
> PS But you should agree with me that
>
> makeAcc := [ :acc |
>        [:n | acc:=acc+n. acc]]
>
> looks a little bit better and concise than
>
> makeAcc := [ :acc |
>        | total |
>        total:=acc.
>        [:n | total:=total+n. total]]

There's no need to explicitly return 'total' from the inner block, because
the assignment yields the same value:

makeAcc := [ :acc |
  | total |
  total := acc.
  [ :n | total := total + n ] ]


Levente

>
> :-)
>
> And thanks for the links.
>
>
>
> --
> View this message in context: http://forum.world.st/Modify-block-closure-parameters-tp4702118p4702410.html
> Sent from the Squeak - Beginners mailing list archive at Nabble.com.
> _______________________________________________
> 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: Modify block (closure) parameters

Edwin Castro
On 8/7/13 12:33 PM, Levente Uzonyi wrote:

> On Wed, 7 Aug 2013, psea wrote:
>
>> What's worried me is that in other languages I'm familiar with it's a
>> normal
>> thing to assign to a function argument (Scheme, C, Python, JavaScript).
>
> Storing into a block or method argument is considered bad practice.
> Support for it is/was planned to be removed. Even though it can yield
> somewhat better performance, it's something you'll rarely see in
> Smalltalk code.

Why is storing into a block or method argument considered bad practice?
Better performance seems like a good reason to follow the practice. I
must assume there are dangers, non-obvious to beginners like me, which
causes the practice to become bad. Of course, one reason is that Squeak
doesn't properly support it today but as mentioned earlier other ST
systems support the practice so I'm curious what causes it to be
considered bad.

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

Re: Modify block (closure) parameters

Yoshiki Ohshima-3
At Wed, 07 Aug 2013 15:05:56 -0700,
Edwin Castro wrote:

>
> On 8/7/13 12:33 PM, Levente Uzonyi wrote:
> > On Wed, 7 Aug 2013, psea wrote:
> >
> >> What's worried me is that in other languages I'm familiar with it's a
> >> normal
> >> thing to assign to a function argument (Scheme, C, Python, JavaScript).
> >
> > Storing into a block or method argument is considered bad practice.
> > Support for it is/was planned to be removed. Even though it can yield
> > somewhat better performance, it's something you'll rarely see in
> > Smalltalk code.
>
> Why is storing into a block or method argument considered bad practice?
> Better performance seems like a good reason to follow the practice. I
> must assume there are dangers, non-obvious to beginners like me, which
> causes the practice to become bad. Of course, one reason is that Squeak
> doesn't properly support it today but as mentioned earlier other ST
> systems support the practice so I'm curious what causes it to be
> considered bad.

One reason is that it would prevent the edit and restart debug session
from being effective.   If some arguments are rewritten by the time
you decided to restart the context, you don't get a repeatable result.

The above being one reason, the overall design that any program should
aspire to was to make functions/methods/blocks pure froms side-effects
whenever possible, and actions/side-effecting part isolated.  Dan and
Alan both have written and talked about that idea.

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

Re: Modify block (closure) parameters

psea
In reply to this post by Levente Uzonyi-2
> It's a compiler bug. The compiler doesn't handle this case.

Let's summarize. Squeak doesn't handle proper an assignment to a block argument and it is a bug. But anyway, assignment to a block argument is considered bad practice so let's just forbid assignment to a block argument thus get rid of the bug. That is "Scanner allowBlockArgumentAssignment: false" is used for.

Is it right?
And does other ST implementations follow the same way?
I've checked: Pharo2.0 does not allow and Pharo3.0 does allow assignment to block argument.
VA Smalltalk doesn't allow changing block arguments (thanks Louis)
Reply | Threaded
Open this post in threaded view
|

Re: Modify block (closure) parameters

psea
GNU Smalltalk also doesn't allow changing block arguments.