I am confused by this piece of code:
| a b c| a := 1. b := [a := a + 1]. c := [a := a - 2. b].
10 timesRepeat: (a even ifTrue: b ifFalse: c). a
My assumption was that this piece of code would set a to -19. Each iteration would test if a was even, but a would be odd so c would be called, substracting 2 from a without affecting its parity. c would not call b because, if my understanding of blocks is correct, the last element of the block is returned instead of evaluated; so c would return b, but timesRepeat discards whatever is returned anyway so this b in c has no effect.
My assumption was proven to be wrong: this piece of code sets a to 9 instead. To see what's going on I modified this piece of code slightly:
| a b c| a := 1. b := [Transcript show: (a displayString). a := a + 1]. c := [Transcript show: (a displayString). a := a - 2. b.].
10 timesRepeat: (a even ifTrue: b ifFalse: c). a
This is what gets printed:
1-1012345678
So it would seem b is called after all? Was my assumption wrong that b is returned instead of called?
Let's try to check this:
jkl := [Transcript show: 'I am called too.'].
asdf := [Transcript show: 'I am called!'. jkl].
10 timesRepeat: asdf
Nope, asdf does not call jkl here:
I am called!I am called!I am called!I am called!I am called!I am called!I am called!I am called!I am called!I am called!
And anyway, if c was always just calling b, its effect would be to effectively substract 1 from a; but this doesn't happen. Instead, the first iteration seems to call c and then, mysteriously, each iteration seems to call b instead, even if a is odd!!
What's going on here??
The timesRepeat: selector wants a block as an argument. You are calling it with an expression inside of parentheses:
10 timesRepeat: (a even ifTrue: b ifFalse: c).
It just so happens, though, that c is defined as the block [a := a - 2. b] which returns the value of b and that happens to be a block. So timesRepeat: is happy, and it executes the block b on each iteration in which a is odd. If you write it correctly as:
10 timesRepeat: [a even ifTrue: b ifFalse: c].
Then at the end, a will be -19 as expected.
Regarding your statement: if my understanding of blocks is correct, the last element of the block is returned instead of evaluated, this isn't really the case. There's no special treatment for the last statement in a block other than it's result is indeed returned as the value of the block when that block is executed. Your last statement in the block is just the name of a variable. The value of the variable just happens to be a block, but no matter what it is, just having a variable name by itself as a statement in Smalltalk just returns the value of the variable. If the variable happens to be a block, you get the block. The block is not executed.
Consider the following blocks:
[a := 1. b := 2. c := a+b]
When this block is executed, then a will have the value 1, b the value 2, and c the value 3. The value the block will return is the value of c, which is 3.
[a := 1. b := 2. a]
If you execute this block, the result will be the value of a, which is 1.
[a := 1. b := 2. c := [a+b]. c]
If you execute this block, the result will be the block that the variable c represents. It does not execute the block c. This is consistent with the prior example.
So, when you execute the block, [Transcript show: 'I am called!'. jkl]., the jkl at the end is not executed. It's value is just returned. If you want to execute it, you could write asdf := [Transcript show: 'I am called!'. jkl value]. A block will execute when sent the value message. The result of executing block [Transcript show: 'I am called!'. jkl value]. will be the result of executing the block jkl.
I may be the only one, but I find the second sentence below a little bit obscure:
It just so happens, though, that c is defined as the block [a := a - 2. b] which returns the value of b and that happens to be a block. So timesRepeat: is happy, and it executes the block b on each iteration in which a is odd.
The semantics of Smalltalk is:
The order is crucial because evaluations may have side effects.
So, what actually happens is:
10 evaluates to 10a even ifTrue: b ifFalse: c evaluates to b. Side effect a = -1.10 timesRepeat: b or 10 timesRepeat: [a := a + 1] is sentHence, a = 9.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With