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.
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:
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 denis.lukichev@gmail.com 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 Beginners@lists.squeakfoundation.org http://lists.squeakfoundation.org/mailman/listinfo/beginners
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.
-- View this message in context: http://forum.world.st/Modify-block-closure-parameters-tp4702118p4702265.html Sent from the Squeak - Beginners mailing list archive at Nabble.com.
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 denis.lukichev@gmail.com 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 Beginners@lists.squeakfoundation.org http://lists.squeakfoundation.org/mailman/listinfo/beginners
Hi Guys,
FWIW, VA Smalltalk doesn't allow changing block arguments.
Lou
On Tue, 6 Aug 2013 13:42:33 -0700, Casey Ransberger casey.obrien.r@gmail.com 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 denis.lukichev@gmail.com 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 Beginners@lists.squeakfoundation.org http://lists.squeakfoundation.org/mailman/listinfo/beginners
----------------------------------------------------------- Louis LaBrunda Keystone Software Corp. SkypeMe callto://PhotonDemon mailto:Lou@Keystone-Software.com http://www.Keystone-Software.com
These should be informative:
http://www.mirandabanda.org/cogblog/2008/06/07/closures-part-i/ http://www.mirandabanda.org/cogblog/2008/07/22/closures-part-ii-the-bytecode... http://www.mirandabanda.org/cogblog/2008/07/24/closures-part-iii-the-compile...
On Tue, Aug 6, 2013 at 2:14 PM, Louis LaBrunda Lou@keystone-software.comwrote:
Hi Guys,
FWIW, VA Smalltalk doesn't allow changing block arguments.
Lou
On Tue, 6 Aug 2013 13:42:33 -0700, Casey Ransberger casey.obrien.r@gmail.com 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 denis.lukichev@gmail.com 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 Beginners@lists.squeakfoundation.org http://lists.squeakfoundation.org/mailman/listinfo/beginners
Louis LaBrunda Keystone Software Corp. SkypeMe callto://PhotonDemon mailto:Lou@Keystone-Software.com http://www.Keystone-Software.com
Beginners mailing list Beginners@lists.squeakfoundation.org http://lists.squeakfoundation.org/mailman/listinfo/beginners
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.
-- 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.
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 Beginners@lists.squeakfoundation.org http://lists.squeakfoundation.org/mailman/listinfo/beginners
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
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
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)
-- View this message in context: http://forum.world.st/Modify-block-closure-parameters-tp4702118p4702700.html Sent from the Squeak - Beginners mailing list archive at Nabble.com.
GNU Smalltalk also doesn't allow changing block arguments.
-- View this message in context: http://forum.world.st/Modify-block-closure-parameters-tp4702118p4702906.html Sent from the Squeak - Beginners mailing list archive at Nabble.com.
beginners@lists.squeakfoundation.org