Blocks & Closures
A block is a piece of deferred code — a lexical closure — written in square brackets:
10.1 Blocks are objects
A block is a piece of deferred code — a lexical closure — written in square brackets:
A block returns the value of its last expression.
| square |
square := [ :x | x * x ]. "a block with one argument"
square value: 5. "→ 25"
[ 3 + 4 ] value. "→ 7 (no arguments)"
[ :a :b | a + b ] value: 1 value: 2. "→ 3"
[ :a :b :c | a + b + c ] value: 1 value: 2 value: 3.
[ :a :b :c :d | a + b + c + d ] value: 1 value: 2 value: 3 value: 4.
[ :a :b | a * b ] valueWithArguments: #(6 7). "→ 42"
[ :x | x ] numArgs. "→ 1"10.2 Block temporaries
[ :x | | doubled | doubled := x * 2. doubled + 1 ] value: 10. "→ 21"10.3 Closures capture variables
Blocks capture variables (not values): if the outer variable changes, the block sees the change.
| counter makeCounter c1 c2 |
makeCounter := [ | count | count := 0. [ count := count + 1 ] ].
c1 := makeCounter value.
c2 := makeCounter value.
c1 value. c1 value. "→ 2"
c2 value. "→ 1 — each closure has its own captured 'count'"10.4 Non-local return
^ inside a block returns from the method in which the block was defined (its *home* method), not just from the block:
If the home method has already returned when the block executes ^, you get a BlockCannotReturn error. Non-local returns are what make detect:-style early exits and control structures as messages possible.
findFirstNegativeIn: aCollection
aCollection do: [ :each | each < 0 ifTrue: [ ^ each ] ]. "returns from the method"
^ nil10.5 Useful block messages
[ :x | x > 3 ] value: 5. "→ true"
[ 100 factorial ] timeToRun. "→ a Duration"
[ 1/0 ] on: ZeroDivide do: [ :e | 0 ]. "exception handling (Chapter 24)"
[ Transcript show: 'tick'; cr ] fork. "run in a new process (Chapter 34)"
[ :x | x * 2 ] cull: 3. "cull: passes the argument only if the block takes one"
[ 42 ] cull: 3. "→ 42"
[ 5 ] ensure: [ Transcript show: 'always runs' ].10.6 Symbols as blocks
Many collection methods accept a symbol where a one-argument block is expected, because Symbol>>value: sends itself to the argument:
#(1 2 3) collect: #squared. "→ #(1 4 9)"
#(1 2 3) collect: [ :n | n squared ]. "same"
#('b' 'a') sorted: #yourself ascending. "Pharo sort functions"