--- a/Block.st Wed Oct 12 07:05:13 2016 +0200
+++ b/Block.st Tue Oct 25 12:31:42 2016 +0100
@@ -49,22 +49,52 @@
is done by the compilers, when some sourceCode is compiled to either
machine or byteCode.
+ In the code, blocks are written as:
+ [
+ expression1.
+ ...
+ expressionN
+ ]
+ It represents the computation inside the brackets,
+ and can be passed around as argument, assigned to variables or returned from a block or method.
+ Creation of a block does NOT evaluate its expressions. You have to give the block to someone,
+ who asks it to evaluate itself. This is done by sending #value to the block.
+ i.e.
+ foo := [ Transcript showCR:'Hello World'].
+ ...
+ foo value
+
+ Blocks are used in many many ways; one particular use is as callback:
+ |b|
+
+ b := Button label:'Press me'.
+ b action:[ Transcript showCR:'Hello'].
+ b open.
+
Blocks with arguments need a message of type ''value:arg1 ... value:argn''
for evaluation; the number of arguments passed when evaluating must match
the number of arguments the block was declared with otherwise an error is
- raised. Blocks without args need a ''value'' message for evaluation.
-
- Blocks keep a reference to the context where the block was declared -
+ raised.
+ Blocks without args need a ''value'' message for evaluation.
+
+ another use of blocks is in the enumeration protocols:
+ |coll|
+
+ coll := #( 'one' 'two' 'three').
+ coll do:[:eachElement | Transcript showCR:eachElement ].
+
+ Blocks keep a reference to the context where it was declared -
this allows blocks to access the methods arguments and/or variables.
This is still true after the method has returned - since the
block keeps this reference, the methods context will NOT die in this case.
- (i.e. Blocks are closures in Smalltalk/X)
+ (for experts: Smalltalk blocks are technically lambdas/closures)
A return (via ^-statement) out of a block will force a return from the
- blocks method context (if it is still living) - this make the implementation
- of long-jumps and control structures possible.
- (If the method is not alive (i.e. has already returned), a return out of the
- block will trigger an error)
+ block's method context (if it is still living).
+ This is effectively a kind of long-jumps out of the method which declared the block
+ and makes control structures and loops possible.
+ If the method is not alive (i.e. has already returned), a return out of the
+ block will trigger an error.
Long-jump is done by defining a catchBlock as ''[^ self]''
somewhere up in the calling-tree. Then, to do the long-jump from out of some
@@ -73,30 +103,30 @@
[Instance variables:]
home <Context> the context where this block was created (i.e. defined)
- this may be a blockContext or a methodContext
+ this may be a blockContext or a methodContext
nargs <SmallInteger> the number of arguments the block expects
sourcePos <SmallInteger> the character position of its source, in chars
- relative to methods source beginning
+ relative to methods source beginning
initialPC <SmallInteger> the start position within the byteCode
- for compiled blocks, this is nil.
+ for compiled blocks, this is nil.
[Class variables:]
InvalidNewSignal raised if a Block is tried to be created
- with new (which is not allowed).
- Only the VM is allowed to create Blocks.
+ with new (which is not allowed).
+ Only the VM is allowed to create Blocks.
NOTICE: layout known by runtime system and compiler - do not change
[author:]
- Claus Gittinger
+ Claus Gittinger
[see also:]
- Process Context
- Collection
- ( contexts. blocks & unwinding : programming/contexts.html)
+ Process Context
+ Collection
+ ( contexts. blocks & unwinding : programming/contexts.html)
"
!
@@ -678,7 +708,6 @@
"Created: / 28-08-2010 / 14:41:15 / cg"
! !
-
!Block methodsFor:'accessing'!
home
@@ -1042,6 +1071,105 @@
"
!
+value:arg1 optionalArgument:arg2 and:arg3 and:arg4
+ "evaluate the receiver.
+ Optionally pass up one, two, three or four arguments
+ (if the receiver is a 1/2/3/4-arg block)."
+
+ nargs == 4 ifTrue:[
+ ^ self value:arg1 value:arg2 value:arg3 value:arg4
+ ].
+ nargs == 3 ifTrue:[
+ ^ self value:arg1 value:arg2 value:arg3
+ ].
+ nargs == 2 ifTrue:[
+ ^ self value:arg1 value:arg2
+ ].
+ ^ self value:arg1
+
+ "
+ |block|
+
+ block := [:arg | Transcript showCR:arg ].
+ block value:1 optionalArgument:2 and:3 and:4.
+
+ block := [:arg1 :arg2 | Transcript show:arg1; space; showCR:arg2 ].
+ block value:1 optionalArgument:2 and:3 and:4.
+
+ block := [:arg1 :arg2 :arg3 :arg4 | Transcript showCR:{arg1 . arg2 . arg3 . arg4}].
+ block value:1 optionalArgument:2 and:3 and:4.
+ "
+!
+
+value:arg1 optionalArgument:arg2 and:arg3 and:arg4 and:arg5
+ "evaluate the receiver.
+ Optionally pass up five arguments
+ (if the receiver is a 1..5-arg block)."
+
+ nargs == 5 ifTrue:[
+ ^ self value:arg1 value:arg2 value:arg3 value:arg4 value:arg5
+ ].
+ nargs == 4 ifTrue:[
+ ^ self value:arg1 value:arg2 value:arg3 value:arg4
+ ].
+ nargs == 3 ifTrue:[
+ ^ self value:arg1 value:arg2 value:arg3
+ ].
+ nargs == 2 ifTrue:[
+ ^ self value:arg1 value:arg2
+ ].
+ ^ self value:arg1
+
+ "
+ |block|
+
+ block := [:arg | Transcript showCR:arg ].
+ block value:1 optionalArgument:2 and:3 and:4 and:5.
+
+ block := [:arg1 :arg2 | Transcript show:arg1; space; showCR:arg2 ].
+ block value:1 optionalArgument:2 and:3 and:4 and:5.
+
+ block := [:arg1 :arg2 :arg3 :arg4 :arg5 | Transcript showCR:{arg1 . arg2 . arg3 . arg4 . arg5}].
+ block value:1 optionalArgument:2 and:3 and:4 and:5.
+ "
+!
+
+value:arg1 optionalArgument:arg2 and:arg3 and:arg4 and:arg5 and:arg6
+ "evaluate the receiver.
+ Optionally pass up six arguments
+ (if the receiver is a 1..6-arg block)."
+
+ nargs == 6 ifTrue:[
+ ^ self value:arg1 value:arg2 value:arg3 value:arg4 value:arg5 value:arg6
+ ].
+ nargs == 5 ifTrue:[
+ ^ self value:arg1 value:arg2 value:arg3 value:arg4 value:arg5
+ ].
+ nargs == 4 ifTrue:[
+ ^ self value:arg1 value:arg2 value:arg3 value:arg4
+ ].
+ nargs == 3 ifTrue:[
+ ^ self value:arg1 value:arg2 value:arg3
+ ].
+ nargs == 2 ifTrue:[
+ ^ self value:arg1 value:arg2
+ ].
+ ^ self value:arg1
+
+ "
+ |block|
+
+ block := [:arg | Transcript showCR:arg ].
+ block value:1 optionalArgument:2 and:3 and:4 and:5 and:6.
+
+ block := [:arg1 :arg2 | Transcript show:arg1; space; showCR:arg2 ].
+ block value:1 optionalArgument:2 and:3 and:4 and:5 and:6.
+
+ block := [:arg1 :arg2 :arg3 :arg4 :arg5 :arg6 | Transcript showCR:{arg1 . arg2 . arg3 . arg4 . arg5 . arg6}].
+ block value:1 optionalArgument:2 and:3 and:4 and:5 and:6.
+ "
+!
+
value:arg1 value:arg2
"evaluate the receiver with two arguments.
The receiver must be a 2-arg block."
@@ -1142,6 +1270,16 @@
^ self wrongNumberOfArguments:3
!
+value:arg1 value:arg2 value:arg3 optionalArgument:arg4
+ "evaluate the receiver.
+ Optionally pass three or four arguments (if the receiver is a 3/4-arg block)."
+
+ nargs == 4 ifTrue:[
+ ^ self value:arg1 value:arg2 value:arg3 value:arg4
+ ].
+ ^ self value:arg1 value:arg2 value:arg3
+!
+
value:arg1 value:arg2 value:arg3 value:arg4
"evaluate the receiver with four arguments.
The receiver must be a 4-arg block."