eXept Software AG Logo

Smalltalk/X Webserver

Documentation of class 'Block':

Home

Documentation
www.exept.de
Everywhere
for:
[back]

Class: Block


Inheritance:

   Object
   |
   +--ExecutableFunction
      |
      +--CompiledCode
         |
         +--Block
            |
            +--CheapBlock
            |
            +--CurryingBlock
            |
            +--VarArgBlock

Package:
stx:libbasic
Category:
Kernel-Methods
Version:
rev: 1.322 date: 2024/02/24 16:59:39
user: cg
file: Block.st directory: libbasic
module: stx stc-classLibrary: libbasic

Description:


Blocks are pieces of executable code which can be evaluated by sending
them a value-message (''value'', ''value:'', ''value:value:'' etc).

In smalltalk, Blocks provide the basic (and heavily used) mechanism
for looping, enumerating collection elements, visitors, exception
handling, unwinding, delayed execution and processes.

Blocks are never created explicitely; the only creation
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.

Another use of blocks is in the enumeration protocols:
    |coll|

    coll := #( 'one' 'two' 'three').
    coll do:[:eachElement | Transcript showCR:eachElement ].

and with map/reduce message like:
    |coll|

    coll := (0 to:100 by:10).
    Transcript showCR:(coll map:[:el | el sqrt])

A block keeps a reference to the context where it was declared -
this allows for blocks to access the method's arguments and/or variables.
This is still true after the method has returned - because
the block keeps this reference, and the method's context will NOT die in this case.
(for experts: Smalltalk blocks are technically lambdas/closures)

A return (via ^-statement) out of a block will force a return from the
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
deeply nested method, simply do: ''catchBlock value''.

Blocks are also used for background threads. Send #fork to a block, to let it
run in the background.

[Instance variables:]

  home        <Context>         the context where this block was created (i.e. defined)
                                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
  initialPC   <SmallInteger>    the start position within the byteCode;
                                this is nil for compiled blocks.


[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.


NOTICE: layout known by runtime system and compiler - do not change

copyright

COPYRIGHT (c) 1989 by Claus Gittinger All Rights Reserved This software is furnished under a license and may be used only in accordance with the terms of that license and with the inclusion of the above copyright notice. This software may not be provided or otherwise made available to, or used by, any other person. No title to or ownership of the software is hereby transferred.

Class protocol:

instance creation
o  byteCode: bCode numArgs: numArgs numStack: nStack sourcePosition: sourcePos initialPC: initialPC literals: literals
create a new cheap (homeless) block.
Not for public use - this is a special hook for the compiler.

o  byteCode: bCode numArgs: numArgs numVars: numVars numStack: nStack sourcePosition: sourcePos initialPC: initialPC literals: literals
create a new cheap (homeless) block.
Not for public use - this is a special hook for the compiler.

o  new
catch creation of blocks - only the system creates blocks.
If you really need a block (assuming, you are some compiler),
use basicNew and setup the instance carefully

o  new: size
catch creation of blocks - only the system creates blocks

queries
o  isBuiltInClass
return true if this class is known by the run-time-system.
Here, true is returned for myself, false for subclasses.


Instance protocol:

Compatibility-ANSI
o  argumentCount
VisualAge/ANSI compatibility: alias for #numArgs.
return the number of arguments I expect for evaluation

o  ensure: aBlock
VisualAge/ANSI compatibility:
evaluate the receiver and return its result.
After evaluation, also evaluate aBlock but ignore its result.
aBlock is always evaluated; i.e. in case of normal or abnormal termination.
(the same as #valueNowOrOnUnwindDo:)

Usage example(s):

     [
	[
	    Transcript showCR:'one'.
	    Processor activeProcess terminate.
	    Transcript showCR:'two'.
	] ensure:[
	    Transcript showCR:'three'.
	].
     ] fork.

Usage example(s):

     [
	[
	    Transcript showCR:'one'.
	    Transcript showCR:'two'.
	] ensure:[
	    Transcript showCR:'three'.
	].
     ] fork.

o  ifCurtailed: aBlock
VisualAge/ANSI compatibility:
evaluate the receiver - when some method sent within unwinds (i.e. does
a long return), evaluate the argument, aBlock.
This is used to make certain that cleanup actions (for example closing files etc.) are
executed regardless of errors, but not if aBlock finishes normally (i.e. not unwinding).
This is the same as #valueOnUnwindDo:
See also ensure:, which ensures that a block is invoked in any case (i.e. also if not unwinding)

Usage example(s):

     |s|

     s := 'Makefile' asFilename readStream.
     [
	^ self
     ] ifCurtailed:[
	Transcript showCR:'closing the stream - even though a return occurred'.
	s close
     ]

Usage example(s):

     [
	 |s|

	 s := 'Makefile' asFilename readStream.
	 [
	    Processor activeProcess terminate
	 ] ifCurtailed:[
	    Transcript showCR:'closing the stream - even though process was terminated'.
	    s close
	 ]
     ] fork

Compatibility-Cola & Pepsi
o  arity
( an extension from the stx:libcompat package )

Compatibility-Dolphin
o  deferredValue
( an extension from the stx:libbasic2 package )
Dolphin compatibility method - do not use in new code.
Dolphin's alias for futureValue

o  deferredValueAt: priority
( an extension from the stx:libbasic2 package )
Dolphin compatibility method - do not use in new code.
Dolphin's alias for futureValueWithPriority:

Compatibility-Squeak
o  cull: optionalFirstArg
( an extension from the stx:libcompat package )
activate the receiver with one or zero arguments.
Squeak compatibility, but also present in VW Smalltalk

o  cull: optionalFirstArg cull: optionalSecondArg
( an extension from the stx:libcompat package )
activate the receiver with two or less arguments.
Squeak compatibility, but also present in VW Smalltalk

o  cull: optionalFirstArg cull: optionalSecondArg cull: optionalThirdArg
( an extension from the stx:libcompat package )
activate the receiver with three or less arguments.
Squeak compatibility, but also present in VW Smalltalk

o  cull: optionalFirstArg cull: optionalSecondArg cull: optionalThirdArg cull: optionalFourthArg
( an extension from the stx:libcompat package )
activate the receiver with four or less arguments.
Squeak compatibility, but also present in VW Smalltalk

o  ifError: handlerBlock
( an extension from the stx:libcompat package )
squeak compatibility:
Evaluate the receiver block and return its value, if no error occurs.
If an error is raised, return the value from handlerBlock.
The handlerBlock may take 0,1 or 2 args.
(1 arg -> the exception;
2 args -> the errorString and the erroneous receiver)

Usage example(s):

     |a|

     a := 0.
     [ 123 / a ] ifError:[:msg :rec | self halt]

Usage example(s):

     |a|

     a := 0.
     [ 123 / a ] ifError:[:ex | self halt]

Usage example(s):

     |a|

     a := 0.
     [ 123 / a ] ifError:[self halt]

o  timeToRun
( an extension from the stx:libcompat package )
squeak compatibility: same as millisecondsToRun:

o  valueWithPossibleArgs: argArray
( an extension from the stx:libcompat package )
squeak compatibility: same as valueWithOptionalArguments:

Compatibility-V'Age
o  apply: aCollection from: start to: end
( an extension from the stx:libcompat package )
VisualAge compatibility:
Evaluate the receiver for each variable slot of aCollection from start to end.
Answer aCollection.

Usage example(s):

     [:i | Transcript showCR:i ]
	apply:#(10 20 30 40 50 60) from:2 to:4

o  applyWithIndex: aCollection from: start to: end
( an extension from the stx:libcompat package )
VisualAge compatibility:
Evaluate the receiver for each variable slot and index of aCollection from start to end.
Answer aCollection.

Usage example(s):

     [:el :i | Transcript showCR:(i -> el) ]
	applyWithIndex:#(10 20 30 40 50 60) from:2 to:4

o  value: arg1 onReturnDo: aBlock
( an extension from the stx:libcompat package )
VisualAge compatibility: alias for #ensure:
evaluate the receiver - when the block returns either a local return
or an unwind (i.e. does a long return), evaluate the argument, aBlock.
This is used to make certain that cleanup actions
(for example closing files etc.) are executed regardless of error actions.

o  value: arg1 value: arg2 onReturnDo: aBlock
( an extension from the stx:libcompat package )
VisualAge compatibility: alias for #ensure:
evaluate the receiver - when the block returns either a local return
or an unwind (i.e. does a long return), evaluate the argument, aBlock.
This is used to make certain that cleanup actions
(for example closing files etc.) are executed regardless of error actions.

o  value: arg1 value: arg2 value: arg3 onReturnDo: aBlock
( an extension from the stx:libcompat package )
VisualAge compatibility: alias for #ensure:
evaluate the receiver - when the block returns either a local return
or an unwind (i.e. does a long return), evaluate the argument, aBlock.
This is used to make certain that cleanup actions
(for example closing files etc.) are executed regardless of error actions.

o  valueOnReturnDo: aBlock
( an extension from the stx:libcompat package )
VisualAge compatibility: alias for #ensure:
evaluate the receiver - when the block returns either a local return
or an unwind (i.e. does a long return), evaluate the argument, aBlock.
This is used to make certain that cleanup actions
(for example closing files etc.) are executed regardless of error actions.

o  when: exceptionClassOrSignal do: handler
( an extension from the stx:libcompat package )
VisualAge compatibility:

Javascript support
o  _at: index
this is a synthetic selector, generated by the compiler,
if a construct of the form expr[idx] is parsed.
I.e.
foo[n]
generates
foo _at: n

o  _at: index1 at: index2
this is a synthetic selector, generated by the compiler,
if a construct of the form expr[idx1][idx2] is parsed.
I.e.
foo[n][m]
generates
foo _at:n at:m

o  _at: index1 at: index2 at: index3
this is a synthetic selector, generated by the compiler,
if a construct of the form expr[idx1][idx2][idx3] is parsed.
I.e.
foo[n][m][o]
generates
foo _at:n at:m at:o

o  _at: index1 at: index2 at: index3 at: index4
this is a synthetic selector, generated by the compiler,
if a construct of the form expr[idx1][idx2][idx3][idx4] is parsed.
I.e.
foo[n][m][o][o]
generates
foo _at:n at:m at:o at:p

o  js_typeof
( an extension from the stx:libjavascript package )
return a string describing what I am

accessing
o  home
return the receiver's home context (the context where it was
created). For cheap blocks, nil is returned

o  homeMethod
return the receiver's home method.
That's the method where the block was created.

o  method
return the receiver's method
(the method where the block was created).
Obsolete: use #homeMethod for ST80 compatibility.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  methodHome
return the receiver's method home context (the context where it was
defined). For cheap blocks, nil is returned

o  numArgs
but left in for a while, for performance and Squeak compatibility

** This is an obsolete interface - do not use it (it may vanish in future versions) **

conversion
o  asBlock
return myself; I am a block

o  asIterator
( an extension from the stx:libbasic2 package )
return myself as an iterator.
that is a collection which uses the receiver block to
generate the elements.

Usage example(s):

     |coll|
     
     coll := [:action | 1 to:20 do:action] asIterator.
     coll do:[:each | Transcript showCR:each].

o  asVarArgBlock
convert myself into a varArg block;
this one has 1 formal argument, which gets the list
of actual arguments when evaluated
(similar to &rest-arg in scheme).

Usage example(s):

     |b|

     b := [:argList |
	    Transcript
		show:'invoked with args:';
		showCR:argList
	  ] asVarArgBlock.
     b value.
     b value:'arg1'.
     b value:'arg1' value:'arg2' value:'arg3' value:'arg4'

o  beCurryingBlock
( an extension from the stx:libbasic2 package )
make myself a currying block;
that's a block which, if invoked with less-than-expected arguments,
returns another block which provides the provided argument(s) and expects the remaining args.
Read any book on functional programming, if you don't understand this.

Usage example(s):

     |b b1 b2 b3|

     b := [:a :b :c | a + b + c] beCurryingBlock.
     b numArgs.
     b value:1 value:2 value:3.

     b1 := b value:10.
     b1 numArgs.
     b1 value:2 value:3.

     b2 := b value:10 value:20.
     b2 numArgs.
     b2 value:3.

     b3 := b1 value:20.
     b3 numArgs.
     b3 value:3.

o  beVarArg
a name alias for asVarArgBlock for compatibility.
Convert myself into a varArg block;
this one has 1 formal argument, which gets the list
of actual arguments when evaluated.

Usage example(s):

     |b|

     b := [:argList | argList printCR] beVarArg.
     b value.
     b value:'arg1' value:'arg2' value:'arg3' value:'arg4'

o  literalArrayEncoding
I have none

copying
o  deepCopyUsing: aDictionary postCopySelector: postCopySelector
(comment from inherited method)
a helper for deepCopy; return a copy of the object with
all subobjects also copied. If the to-be-copied object is in the dictionary,
use the value found there. The class of the receiver is not copied.
This method DOES handle cycles/self references.

debugging
o  benchmark: anInfoString
evaluate myself and show the timing info on Transcript.
Notice: the time values depend heavily on external factors
(i.e. is there an interrupt; is the CPU doing I/O; are there other processes running etc.)
Therefore, for short time code, run your code multiple times and divide by the number of runs.
As seen in the examples at the end, the times are much more consistent then.

Usage example(s):

     be aware that if you evaluate the following,
     the blocks will be interpreted by the doIt.
     Thus, depending on your settings, you will get unrealistic values.
     Better compile those expressions into a method and call that
     for realistic measurements.

     [] benchmark:'empty block'        - this is a pre-compiled block
     [123] benchmark:'empty block'     - the rest are interpreted blocks
     [10 factorial] benchmark:'10 factorial'
     [20 factorial] benchmark:'20 factorial'
     [30 factorial] benchmark:'30 factorial'
     [100 factorial] benchmark:'100 factorial'

     [30 factorial] benchmark:'30 factorial'
     [100 timesRepeat:[30 factorial]] benchmark:'100 * 30 factorial'
     [1000 timesRepeat:[30 factorial]] benchmark:'1000 * 30 factorial'
     [100000 timesRepeat:[30 factorial]] benchmark:'100000 * 30 factorial'

o  benchmark: anInfoString timeLimit: timeLimitOrNil
evaluate myself and show the timing info on Transcript.
Notice: the time values depend heavily on external factors
(i.e. is there an interrupt; is the CPU doing I/O; are there other processes running etc.)
Therefore, for short time code, run your code multiple times and divide by the number of runs,
or (better) take the minimum time (as that is the time with the smallest external influence).
As seen in the examples at the end, the times are much more consistent then.

Usage example(s):

     be aware that if you evaluate the following,
     the blocks will be interpreted by the doIt.
     Thus, depending on your settings, you will get unrealistic values.
     Better compile those expressions into a method and call that
     for realistic measurements.

     [] benchmark:'empty block'        - this is a pre-compiled block
     [123] benchmark:'empty block'     - the rest are interpreted blocks
     [10 factorial] benchmark:'10 factorial'
     [20 factorial] benchmark:'20 factorial'
     [30 factorial] benchmark:'30 factorial'
     [100 factorial] benchmark:'100 factorial'

     [30 factorial] benchmark:'30 factorial'
     [100 timesRepeat:[30 factorial]] benchmark:'100 * 30 factorial'
     [1000 timesRepeat:[30 factorial]] benchmark:'1000 * 30 factorial'
     [100000 timesRepeat:[30 factorial]] benchmark:'100000 * 30 factorial'

error handling
o  invalidCodeObject
this error is triggered by the interpreter when a non-Block object
is about to be executed.
In this case, the VM sends this to the bad method (the receiver).
Can only happen when the Compiler/runtime system is broken or
someone played around.

evaluation
o  value
evaluate the receiver with no block args.
The receiver must be a block without arguments.

o  value: arg
evaluate the receiver with one argument.
The receiver must be a 1-arg block.

o  value: arg1 optionalArgument: arg2
evaluate the receiver.
Optionally pass one or to two arguments (if the receiver is a one/two arg block).

Usage example(s):

     |block|

     block := [:arg | Transcript showCR:arg ].
     block value:2 optionalArgument:3.

     block := [:arg1 :arg2 | Transcript show:arg1; space; showCR:arg2 ].
     block value:2 optionalArgument:3.

o  value: arg1 optionalArgument: arg2 and: arg3
evaluate the receiver.
Optionally pass one, two or three arguments (if the receiver is a 1/2/3-arg block).

Usage example(s):

     |block|

     block := [:arg | Transcript showCR:arg ].
     block value:2 optionalArgument:3.

     block := [:arg1 :arg2 | Transcript show:arg1; space; showCR:arg2 ].
     block value:2 optionalArgument:3.

o  value: arg1 optionalArgument: arg2 and: arg3 and: arg4
evaluate the receiver.
Optionally pass one, two, three or four arguments
(if the receiver is a 1/2/3/4-arg block).

Usage example(s):

     |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.

o  value: arg1 optionalArgument: arg2 and: arg3 and: arg4 and: arg5
evaluate the receiver.
Optionally pass up to five arguments
(if the receiver is a 1..5-arg block).

Usage example(s):

     |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.

o  value: arg1 optionalArgument: arg2 and: arg3 and: arg4 and: arg5 and: arg6
evaluate the receiver.
Optionally pass up to six arguments
(if the receiver is a 1..6-arg block).

Usage example(s):

     |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.

o  value: arg1 value: arg2
evaluate the receiver with two arguments.
The receiver must be a 2-arg block.

o  value: arg1 value: arg2 optionalArgument: arg3
evaluate the receiver.
Optionally pass two or three arguments (if the receiver is a 2/3-arg block).

o  value: arg1 value: arg2 value: arg3
evaluate the receiver with three arguments.
The receiver must be a 3-arg block.

o  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).

o  value: arg1 value: arg2 value: arg3 value: arg4
evaluate the receiver with four arguments.
The receiver must be a 4-arg block.

o  value: arg1 value: arg2 value: arg3 value: arg4 value: arg5
evaluate the receiver with five arguments.
The receiver must be a 5-arg block.

o  value: arg1 value: arg2 value: arg3 value: arg4 value: arg5 value: arg6
evaluate the receiver with six arguments.
The receiver must be a 6-arg block.

o  value: arg1 value: arg2 value: arg3 value: arg4 value: arg5 value: arg6 value: arg7
evaluate the receiver with seven arguments.
The receiver must be a 7-arg block.

o  value: arg1 value: arg2 value: arg3 value: arg4 value: arg5 value: arg6 value: arg7 value: arg8
evaluate the receiver with eight arguments.
The receiver must be a 8-arg block.

o  value: arg1 value: arg2 value: arg3 value: arg4 value: arg5 value: arg6 value: arg7 value: arg8 value: arg9
evaluate the receiver with 9 arguments.
The receiver must be a 9-arg block.

o  value: arg1 value: arg2 value: arg3 value: arg4 value: arg5 value: arg6 value: arg7 value: arg8 value: arg9 value: arg10
evaluate the receiver with 10 arguments.
The receiver must be a 10-arg block.

o  value: arg1 value: arg2 value: arg3 value: arg4 value: arg5 value: arg6 value: arg7 value: arg8 value: arg9 value: arg10 value: arg11
evaluate the receiver with 11 arguments.
The receiver must be a 11-arg block.

o  value: arg1 value: arg2 value: arg3 value: arg4 value: arg5 value: arg6 value: arg7 value: arg8 value: arg9 value: arg10 value: arg11 value: arg12
evaluate the receiver with 12 arguments.
The receiver must be a 12-arg block.

o  valueAt: priority
evaluate the receiver, at the given prioriy;
i.e. change the priority for the execution of the receiver.
Bad name: should be called evaluateWithPriority: or similar

Usage example(s):

     [
	 10000 factorial
     ] valueAt:3

o  valueWithArguments: argArrayIn
evaluate the receiver with arguments taken from argArray.
ArgArray must be either an Array or nil.
The size of the argArray must match the number of arguments the receiver expects.

Usage example(s):

	[:a :b :c | Transcript showCR:a; showCR:b; showCR:c] valueWithArguments:#(1 2 3).
	[:a :b :c | Transcript showCR:a; showCR:b; showCR:c] valueWithArguments:#(1 2 3) asOrderedCollection.

o  valueWithOptionalArgument: arg
evaluate the receiver.
Optionally pass an argument (if the receiver is a one arg block).

Usage example(s):

     |block|

     block := [ Transcript showCR:'hello' ].
     block valueWithOptionalArgument:2.

     block := [:arg | Transcript showCR:arg ].
     block valueWithOptionalArgument:2.

o  valueWithOptionalArgument: arg1 and: arg2
evaluate the receiver.
Optionally pass up to two arguments (if the receiver is a one/two arg block).

Usage example(s):

     |block|

     block := [ Transcript showCR:'hello' ].
     block valueWithOptionalArgument:2.

     block := [:arg | Transcript showCR:arg ].
     block valueWithOptionalArgument:2.

     block := [:arg1 :arg2 | Transcript showCR:arg1. Transcript showCR:arg2 ].
     block valueWithOptionalArgument:10 and:20.

o  valueWithOptionalArgument: arg1 and: arg2 and: arg3
evaluate the receiver.
Optionally pass up to three arguments (if the receiver is a one/two/three arg block).

Usage example(s):

     |block|

     block := [ Transcript showCR:'hello' ].
     block valueWithOptionalArgument:2.

     block := [:arg | Transcript showCR:arg ].
     block valueWithOptionalArgument:2.

     block := [:arg1 :arg2 | Transcript showCR:arg1. Transcript showCR:arg2 ].
     block valueWithOptionalArgument:10 and:20.

o  valueWithOptionalArgument: arg1 and: arg2 and: arg3 and: arg4
evaluate the receiver.
Optionally pass up to four arguments (if the receiver is a one/two/three/four arg block).

Usage example(s):

     |block|

     block := [ Transcript showCR:'hello' ].
     block valueWithOptionalArgument:2.

     block := [:arg | Transcript showCR:arg ].
     block valueWithOptionalArgument:2.

     block := [:arg1 :arg2 | Transcript showCR:arg1. Transcript showCR:arg2 ].
     block valueWithOptionalArgument:10 and:20.

o  valueWithOptionalArguments: argArrayIn
evaluate the receiver with arguments as required taken from argArray.
Only the required number of arguments is taken from argArray or nil;
(i.e. argArray may be larger than the required number).
If the size of the argArray is smaller than the number of arguments, an error is raised.

Usage example(s):

	[:a :b :c | Transcript showCR:a; showCR:b; showCR:c] valueWithOptionalArguments:#(1 2 3 4).
	[:a :b :c | Transcript showCR:a; showCR:b; showCR:c] valueWithOptionalArguments:#(1 2 3 4) asOrderedCollection.

o  valueWithPossibleArguments: argArrayIn
evaluate the receiver with arguments as required taken from argArray.
If argArray provides less than the required number of arguments,
nil is assumed for any remaining argument.
(i.e. argArray may be smaller than the required number).
Only the required number of arguments is taken from argArray or nil;
(i.e. argArray may be larger than the required number).

Usage example(s):

	[:a :b :c :d| Transcript showCR:a; showCR:b; showCR:c; showCR:d] valueWithPossibleArguments:#(1 2 3).
	[:a :b :c :d| Transcript showCR:a; showCR:b; showCR:c; showCR:d] valueWithPossibleArguments:#(1 2 3 4 5).
	[:a :b :c :d| Transcript showCR:a; showCR:b; showCR:c; showCR:d] valueWithPossibleArguments:#(1 2 3) asOrderedCollection.

evaluation with timeout
o  valueWithConfirmedTimeout: secondsOrTimeDuration confirmWith: confirmationBlock
evaluate the receiver.
If not finished after secondsOrTimeDuration, call the confirmationBlock.
If it returns true, another time-interval is setup and we continue waiting.
If it returns a number (seconds) or a timeDuration, this time-interval is setup and we continue waiting.
If it returns false, nil is returned immediately.
The execution is proceeded while the confirmationBlock is called and the latter is terminated in case
the execution terminates in the meantime.

The receiver's code must be prepared
for premature returning (by adding ensure blocks, as required)

Usage example(s):

     [
	1 to:10 do:[:i |
	    Transcript showCR:i.
	    1 seconds wait.
	].
	'finished'
     ] valueWithConfirmedTimeout:(3 seconds) confirmWith:[
	Dialog confirm:'continue (waiting 3 more seconds)?'
     ].

Usage example(s):

     [
	1 to:10 do:[:i |
	    Transcript showCR:i.
	    1 seconds wait.
	].
	'finished'
     ] valueWithConfirmedTimeout:(3 seconds) confirmWith:[
	(Dialog confirm:'wait another 5 seconds?') ifTrue:[
	    5 seconds
	] ifFalse:[
	    false
	].
     ].

o  valueWithTimeout: aTimeDurationOrIntegerSeconds
execute the receiver, but abort the evaluation after aTimeDuration if still running.
Return the receiver's value, or nil if aborted due to a timeout.

The receiver's code must be prepared
for premature returning (by adding ensure blocks, as required)

Usage example(s):

     [
	1 to:15 do:[:round |
	    Transcript showCR:round.
	    Delay waitForMilliseconds:20.
	].
	true
     ] valueWithTimeout:(TimeDuration seconds:1)

Usage example(s):

     [
	1 to:100 do:[:round |
	    Transcript showCR:round.
	    Delay waitForMilliseconds:20.
	].
	true
     ] valueWithTimeout:(TimeDuration seconds:1)

o  valueWithWatchDog: exceptionBlock afterMilliseconds: aTimeLimit
a watchdog on a block's execution. If the block does not finish its
evaluation after aTimeLimit milliseconds, it is interrupted (aborted) and
exceptionBlock's value is returned.

The receiver's code must be prepared
for premature returning (by adding ensure blocks, as required)

Usage example(s):

timeout happens; but true is returned after debugging is finished.
     [
	self proceedableError:'to show a debugger'.
	true
     ] valueWithWatchDog:[false] afterMilliseconds:1000

exception handling
o  on: aSignalOrSignalSetOrException do: exceptionBlock
added for ANSI compatibility; evaluate the receiver,
handling aSignalOrSignalSetOrException.
If the signal is raised during evaluation,
the 2nd argument, exceptionBlock is evaluated (and its value returned)

Usage example(s):

     [
	1 foo
     ] on:MessageNotUnderstood do:[:ex | self halt]

     [
	1 foo
     ] on:(MessageNotUnderstood , AbortOperationRequest) do:[:ex | self halt]

     [
	1 foo
     ] on:SignalSet anySignal do:[:ex| 2 bar. self halt]

     [
	1 foo
     ] on:Error do:[:ex| 2 ]

o  on: aSignalOrSignalSetOrException do: exceptionBlock ensure: ensureBlock
added for ANSI compatibility; evaluate the receiver,
handling aSignalOrSignalSetOrException.
The 2nd argument, exceptionBlock is evaluated
if the signal is raised during evaluation.
The 3rd argument, ensureBlock is evaluated in any case - even if the activity
was unwound due to an unhandled exception.

Usage example(s):

     |e|

     e := 0.
     [
	1 foo
     ] on:MessageNotUnderstood do:[:ex |
	self halt
     ] ensure:[
	e := 1
     ].
     self assert:(e == 1).

Usage example(s):

     [
	1 foo
     ] on:MessageNotUnderstood do:[:ex |
	^ self
     ] ensure:[
	Transcript showCR:'ensure ensured'
     ].

Usage example(s):

     |e|

     e := 0.
     [
	1 negated
     ] on:MessageNotUnderstood do:[:ex |
	self halt
     ] ensure:[
	e := 1
     ].
     self assert:(e == 1).

o  on: aSignalOrSignalSetOrException do: exceptionBlock ifCurtailed: curtailBlock
evaluate the receiver,
handling aSignalOrSignalSetOrException.
The 2nd argument, exceptionBlock is evaluated
if the signal is raised during evaluation.
The 3rd argument, curtailBlock is evaluated if the activity
was unwound due to an unhandled exception in the receiver block
(but not in the exceptionBlock).

Usage example(s):

     |e|

     e := 0.
     [
	1 foo
     ] on:MessageNotUnderstood
     do:[:ex | e := 1]
     ifCurtailed:[ e := 2 ].
     self assert:(e == 1).

Usage example(s):

     abort the debugger to perform the ifCurtailedBlock...
     continue the debugger to go to the end

     |e|

     e := 0.
     [
	#[] at:2
     ] on:MessageNotUnderstood
     do:[:ex | e := 1]
     ifCurtailed:[ e := 2. e inspect ].
     self assert:(e == 0).

Usage example(s):

     |e|

     e := 0.
     [
	1 negated
     ] on:MessageNotUnderstood
     do:[:ex | self halt]
     ifCurtailed:[ e := 1 ].
     self assert:(e == 0).

Usage example(s):

     |e|

     e := 0.
     [
	1 foo
     ] on:MessageNotUnderstood do:[:ex | 2 bla]
       ifCurtailed:[ e := 1 ].
     self assert:(e == 0).

o  on: anExceptionHandler do: exceptionBlock on: anExceptionHandler2 do: exceptionBlock2
added for ANSI compatibility; evaluate the receiver.
Evalute exceptionBlock if anExceptionHandler is raised during evaluation.
Evalute exceptionBlock2 if anExceptionHandler2 is raised during evaluation.
Note: an error raised in one handler block are not handled by the other handler block.

Usage example(s):

     [
	1 foo
     ] on:MessageNotUnderstood do:[:ex | self halt:'Got MessageNotUnderstood']
       on:Error do:[:ex| self halt:'Got Error']

     Note: error originating form one handler block are not handled by the other handler block:

     [
	1 foo
     ] on:MessageNotUnderstood do:[:ex | 1 // 0]
       on:Error do:[:ex| self halt:'Got Error from MessageNotUnderstood handler block']

     [
	1 // 0
     ] on:MessageNotUnderstood do:[:ex | self halt:'Got MessageNotUnderstood']
       on:Error do:[:ex| self halt:'Got Error']

o  valueWithExceptionHandler: handler
evaluate myself. If any of the signals in handler is raised,
evaluate the corresponding handler block.

exception handling private
o  exceptionHandlerFor: anException in: aContext
answer the exceptionHandler (the Error or signal) for anException from aContext.

o  handlerForSignal: exceptionCreator context: aContext originator: originator
answer the handler block for the exceptionCreator from originator.
The handler block is retrieved from aContext.
Answer nil if the exceptionCreator is not handled.

o  handlerProtectedBlock: doBlock inContext: context
set the block that is protected by an exception handler in context.
This is the receiver of the #on:do: or #valueWithExceptionHandler:.
Needed for #restartDo:

inspecting
o  inspector2TabClassOfHome
( an extension from the stx:libtool package )
another tab browsing the block's home method

o  inspectorExtraAttributes
( an extension from the stx:libtool package )
extra (pseudo instvar) entries to be shown in an inspector.

looping
o  doUntil: aBlock
repeat the receiver block until aBlock evaluates to true.
The receiver is evaluated at least once.
This is the same as '... doWhile:[... not]'

Usage example(s):

     |n|

     n := 1.
     [Transcript showCR:n] doUntil:[ (n := n + 1) > 5 ]

o  doWhile: aBlock
repeat the receiver block until aBlock evaluates to false.
The receiver is evaluated at least once.

Usage example(s):

     |n|

     n := 1.
     [Transcript showCR:n] doWhile:[ (n := n + 1) <= 5 ]

o  doWhileFalse: aBlock
repeat the receiver block until aBlock evaluates to true.
The receiver is evaluated at least once.

Usage example(s):

     |n|

     n := 1.
     [Transcript showCR:n] doWhileFalse:[ (n := n + 1) > 5 ]

o  loop
repeat the receiver forever
(the receiver block should contain a return somewhere).
The implementation below was inspired by a corresponding Self method.

Usage example(s):

     |n|

     n := 1.
     [
	n printCR.
	n >= 10 ifTrue:[^ nil].
	n := n + 1
     ] loop

o  loopWithExit
the receiver must be a block of one argument. It is evaluated in a loop forever,
and is passed a block, which, if sent a value:-message, will exit the receiver block,
returning the parameter of the value:-message. Used for loops with exit in the middle.
Inspired by a corresponding Self method.

Usage example(s):

     |i ret|
     i := 1.
     ret := [:exit |
	Transcript showCR:i.
	i == 5 ifTrue:[exit value:'thats it'].
	i := i + 1
     ] loopWithExit.
     Transcript showCR: e'ret: {ret}'

Usage example(s):

     |i ret|
     i := 1.
     ret := [:exit |
	Transcript showCR:i.
	i == 5 ifTrue:exit.
	i := i + 1
     ] loopWithExit.
     Transcript showCR: e'ret: {ret}'

o  loopWithExitAndRepeat
the receiver must be a block of two arguments.
It is evaluated in a loop forever, and is passed
an exit block which, if sent a value:-message, will exit the loop with that value.
and a continue which, if sent a value-message, will re-enter the loop from the top.
Used for loops with continue and exit in the middle.
Inspired by the loopWithExit method.

Usage example(s):

     |i ret|
     i := 0.
     [:exit
      :continue |
	i := i + 1.
	i == 5 ifTrue:continue.
	Transcript showCR:i.
	i == 10 ifTrue:exit.
     ] loopWithExitAndRepeat.

o  loopWithRepeat
the receiver must be a block of one argument.
It is evaluated in a loop forever,
and is passed a block, which, if sent a value:-message, will re-enter the loop
from the top.
Used for loops with continue in the middle.
Inspired by the loopWithExit method.

Usage example(s):

     |i ret|
     i := 0.
     [:continue |
	i := i + 1.
	i == 5 ifTrue:continue.
	Transcript showCR:i.
	i == 10 ifTrue:[^ self].
     ] loopWithRepeat.

o  repeat
repeat the receiver forever - same as loop, for ST-80 compatibility.
(the receiver block should contain a return somewhere).

o  repeat: n
repeat the receiver n times - similar to timesRepeat, but optionally passes the
loop counter as argument

o  valueWithExit
the receiver must be a block of one argument. It is evaluated, and is passed a block,
which, if sent a value:-message, will exit the receiver block, returning the parameter of the
value:-message.
Used for premature returns to the caller (for example, to implement break out of a loop).
Taken from a manchester goody (a similar construct also appears in Self).

Usage example(s):

     [:exit |
	1 to:10 do:[:i |
	    Transcript showCR:i.
	    i == 5 ifTrue:[exit value:'thats it']
	].
	'regular block-value; never returned'
     ] valueWithExit

Usage example(s):

     [:exit |
	1 to:10 do:[:i |
	    Transcript showCR:i.
	    i == 5 ifTrue:[exit value]
	].
	'regular block-value; never returned'
     ] valueWithExit

o  valueWithExit: arg
the receiver must be a block of two arguments. It is evaluated, and is passed an argument,
plus a block, which, if sent a value:-message, will exit the receiver block, returning the parameter of the
value:-message.
Used for premature returns to the caller (for example, to implement break out of a loop).
Taken from a manchester goody (a similar construct also appears in Self).

Usage example(s):

     [:arg :exit |
	1 to:10 do:[:i |
	    Transcript show:arg; showCR:i.
	    i == 5 ifTrue:[exit value:'thats it']
	].
	'regular block-value; never returned'
     ] valueWithExit:'hello'

Usage example(s):

     [:arg :exit |
	1 to:10 do:[:i |
	    Transcript show:arg; showCR:i.
	    i == 5 ifTrue:[exit value]
	].
	'regular block-value; never returned'
     ] valueWithExit:'hello'

Usage example(s):

     [:arg :exit |
	1 to:10 do:[:i |
	    Transcript show:arg; showCR:i.
	    i == 15 ifTrue:[exit value:'thats it']
	].
	'regular block-value; never returned'
     ] valueWithExit:'hello'

o  valueWithRestart
the receiver must be a block of one argument. It is evaluated, and is passed a block,
which, if sent a value-message, will restart the receiver block from the beginning.
Used restart a block from the biginning (for example, to implement continue in a loop).

Usage example(s):

     [:restart |
	(self confirm:'try again ?') ifTrue:[
	    restart value.
	]
     ] valueWithRestart

o  valueWithRestartAndExit
the receiver must be a block of two arguments, a restart and an exit block.
See description of valueWithExit and valueWithRestart for their use

Usage example(s):

     [:restart :exit |
	|i|

	i := 0.
	[
	    i := i + 1.
	    (self confirm:('i is ',i printString,'; start over ?')) ifTrue:[
		restart value.
	    ].
	    (self confirm:'enough ?') ifTrue:[
		exit value:nil.
	    ].
	] loop
     ] valueWithRestartAndExit

o  whileFalse
evaluate the receiver while it evaluates to false (ST80 compatibility)

Usage example(s):

     |n|

     n := 1.
     [n printCR. (n := n + 1) > 10] whileFalse

o  whileFalse: aBlock
evaluate the argument, aBlock while the receiver evaluates to false.
- usually open coded by compilers, but needed here for #perform
and expression evaluation.

Usage example(s):

     |n|

     n := 1.
     [n > 10] whileFalse:[
	n printCR.
	n := n + 1
     ]

o  whileTrue
evaluate the receiver while it evaluates to true (ST80 compatibility)

Usage example(s):

     |n|

     n := 1.
     [n printCR. (n := n + 1) <= 10] whileTrue

o  whileTrue: aBlock
evaluate the argument, aBlock while the receiver evaluates to true.
- usually open coded by compilers, but needed here for #perform
and expression evaluation.

Usage example(s):

     |n|

     n := 1.
     [n <= 10] whileTrue:[
	n printCR.
	n := n + 1
     ]

parallel evaluation
o  futureValue
( an extension from the stx:libbasic2 package )
Fork a synchronised evaluation of myself immediately.
Starts the evaluation in parallel now, but synchronizes
any access to wait until the result is computed.

o  futureValue: aValue
( an extension from the stx:libbasic2 package )
Fork a synchronised evaluation of myself immediately.
Starts the evaluation in parallel now, but synchronizes
any access to wait until the result is computed.

o  futureValue: aValue value: anotherValue
( an extension from the stx:libbasic2 package )
Fork a synchronised evaluation of myself immediately.
Starts the evaluation in parallel now, but synchronizes
any access to wait until the result is computed.

o  futureValue: aValue value: anotherValue value: bValue
( an extension from the stx:libbasic2 package )
Fork a synchronised evaluation of myself immediately.
Starts the evaluation in parallel now, but synchronizes
any access to wait until the result is computed.

o  futureValueWithArguments: anArray
( an extension from the stx:libbasic2 package )
Fork a synchronised evaluation of myself immediately.
Starts the evaluation in parallel now, but synchronizes
any access to wait until the result is computed.

o  futureValueWithPriority: prio
( an extension from the stx:libbasic2 package )
Fork a synchronised evaluation of myself immediately.
Starts the evaluation in parallel now, but synchronizes
any access to wait until the result is computed.

o  lazyFutureValue
( an extension from the stx:libbasic2 package )
Fork a synchronised background enqueued evaluation of myself.
Starts the evaluation in parallel in some time, but synchronizes
any access to wait until the result is computed.
Only one backrgound process serves all lazyFutures (aka batch processing).
Use this, if you have cillions of futures to create

o  lazyValue
( an extension from the stx:libbasic2 package )
Return a lazy value object, evaluating myself only when needed.
I will do nothing now and only compute when the result is requested.

o  lazyValue: aValue
( an extension from the stx:libbasic2 package )
Return a lazy value object, evaluating myself only when needed.
I will do nothing now and only compute when the result is requested.

o  lazyValue: aValue value: anotherValue
( an extension from the stx:libbasic2 package )
Return a lazy value object, evaluating myself only when needed.
I will do nothing now and only compute when the result is requested.

o  lazyValue: aValue value: anotherValue value: bValue
( an extension from the stx:libbasic2 package )
Return a lazy value object, evaluating myself only when needed.
I will do nothing now and only compute when the result is requested.

o  lazyValueWithArguments: anArray
( an extension from the stx:libbasic2 package )
Return a lazy value object, evaluating myself only when needed.
I will do nothing now and only compute when the result is requested.

printing & storing
o  printBlockBracketsOn: aStream

o  printOn: aStream
append a a printed representation of the block to aStream

Usage example(s):

home receiver class name printOn:aStream.

Usage example(s):

(h searchClass whichClassImplements:sel) name printOn:aStream.

Usage example(s):

homeClass name printOn:aStream.

Usage example(s):

(homeClass selectorForMethod:home) printOn:aStream

o  storeOn: aStream
(comment from inherited method)
store the receiver on aStream; i.e. print an expression which will
reconstruct the receiver.
Notice, that no self referencing or cyclic objects can be represented
in this format.
Use storeBinaryOn:, which handles these cases correctly.

private-accessing
o  byteCode: bCode numArgs: numArgs numVars: numVars numStack: numStack sourcePosition: srcPos initialPC: iPC literals: lits
set all relevant internals.
DANGER ALERT: this interface is strictly private.

o  initialPC
return the initial pc for evaluation.

o  initialPC: initial
set the initial pc for evaluation.
DANGER ALERT: this interface is for the compiler only.

o  numArgs: numArgs
set the number of arguments the receiver expects for evaluation.
DANGER ALERT: this interface is for the compiler only.

o  setHome: aContext

o  source
misuses the sourcePosition slot

o  source: aString
set the source - only to be used, if the block is not contained in a method.
This interface is for knowledgable users only.

o  sourcePosition: position
set the position of the source within my method.
This interface is for the compiler only.

privileged evaluation
o  valueUninterruptably
evaluate the receiver as an atomic operation
This does not prevent preemption by a higher priority processes
if any becomes runnable due to the evaluation of the receiver
(i.e. if a semaphore is signalled).

o  valueUnpreemptively
evaluate the receiver without the possiblity of preemption
(i.e. at a priority higher than the round-robin scheduler's prio)

process creation
o  fork
create a new process executing the receiver at the current priority.

o  forkAndWait
create a new process executing the receiver at the current priority.
Wait for the process to terminate

o  forkAt: priorityOrRangeOrNil
create a new process executing the receiver at a possibly different priority
or priority range (an Interval).
If priorityOrRangeOrNil is nil, the process runs at the current prio

Usage example(s):

	[Semaphore new wait] forkAt:7.
	[Semaphore new wait] forkAt:(4 to:8).

o  forkAt: priorityOrRangeOrNil named: aStringOrNil
create a new process, give it a name and let it start
executing the receiver at the given priority or priority range (an Interval)
or at the current prio (if nil(.

o  forkNamed: aString
create a new process, give it a name and let it start
executing the receiver at the current priority.

o  forkWith: argArray
create a new process executing the receiver,
passing elements in argArray as arguments to the receiver block.

** This is an obsolete interface - do not use it (it may vanish in future versions) **

o  forkWithArguments: argArray
create a new process executing the receiver,
passing elements in argArray as arguments to the receiver block.

o  newProcess
create a new (unscheduled) process executing the receiver

o  newProcessWithArguments: argArray
create a new (unscheduled) process executing the receiver,
passing the elements in argArray as arguments to the receiver block.

o  promise
( an extension from the stx:libbasic2 package )
create a promise on the receiver. The promise will evaluate the
receiver and promise to return the value with the #value message.
The evaluation will be performed as a separate process.
Asking the promise for its value will either block the asking process
(if the evaluation has not yet been finished) or return the value
immediately.

Usage example(s):

     |p|

     p := [1000 factorial] promise.
     'do something else ...'.
     p value

o  promiseAt: prio
( an extension from the stx:libbasic2 package )
create a promise on the receiver. The promise will evaluate the
receiver and promise to return the value with the #value message.
The evaluation will be performed as a separate process running at prio.
Asking the promise for its value will either block the asking process
(if the evaluation has not yet been finished) or return the value
immediately.

splitting & joining
o  split: aSequenceableCollection indicesDo: aBlock
let me split aSequenceableCollection
and evaluate aBlock for each fragment's start- and end-position.
I myself am invoked for every character, optionally accepting the char-index
as second arg.

testing
o  isBlock
return true, if this is a block - yes I am

o  isBlockWithArgumentCount: count
return true, if this is a block with count args

o  isCheapBlock

o  isVarArgBlock
return true, if this block accepts a variable number of arguments

unwinding
o  unwindHandlerInContext: aContext
given a context which has been marked for unwind,
retrieve the handler block.
This avoids hardwiring access to the first argument in
#unwind methods (and theoretically allows for other unwinding
methods to be added)

unwinding-old
o  value: arg onUnwindDo: aBlock
evaluate the receiver, passing it one argument
- when some method sent within unwinds (i.e. does
a long return), evaluate the argument, aBlock.
This is used to make certain that cleanup actions (for example closing files etc.) are
executed regardless of error actions

Usage example(s):

     |s|

     s := 'Makefile' asFilename readStream.
     [:arg |
	^ self
     ] value:12345 onUnwindDo:[
	Transcript showCR:'closing the stream - even though a return occurred'.
	s close
     ]

Usage example(s):

     [
	 |s|

	 s := 'Makefile' asFilename readStream.
	 [:arg |
	    Processor activeProcess terminate
	 ] value:12345 onUnwindDo:[
	    Transcript showCR:'closing the stream - even though process was terminated'.
	    s close
	 ]
     ] fork

o  valueNowOrOnUnwindDo: aBlock
evaluate the receiver - after that, or when some method sent within unwinds (i.e. does
a long return), evaluate the argument, aBlock.
This is used to make certain that cleanup actions (for example closing files etc.) are
executed regardless of error actions.
Same as the more modern, ANSI standardized #ensure:,
which should be used instead for portability.

Usage example(s):

     |f|

     f := 'Makefile' asFilename readStream.
     [
	l := f nextLine.
	l isNil ifTrue:[^ 'oops']
     ] valueNowOrOnUnwindDo:[
	f close
     ]

o  valueOnUnwindDo: aBlock
evaluate the receiver - when some method sent within unwinds (i.e. does
a long return), evaluate the argument, aBlock.
This is used to make certain that cleanup actions (for example closing files etc.) are
executed regardless of error actions.
Same as the more modern, ANSI standardized #ifCurtailed:,
which should be used instead for portability.

Usage example(s):

     |s|

     s := 'Makefile' asFilename readStream.
     [
	^ self
     ] valueOnUnwindDo:[
	Transcript showCR:'closing the stream - even though a return occurred'.
	s close
     ]

Usage example(s):

     [
	 |s|

	 s := 'Makefile' asFilename readStream.
	 [
	    Processor activeProcess terminate
	 ] valueOnUnwindDo:[
	    Transcript showCR:'closing the stream - even though process was terminated'.
	    s close
	 ]
     ] fork

visiting
o  acceptVisitor: aVisitor with: aParameter
dispatch for visitor pattern; send #visitBlock:with: to aVisitor


Examples:


define a block and evaluate it:
    |b|

    b := [ Transcript showCR:'hello' ].

    Transcript showCR:'now evaluating the block ...'.
    b value.
even here, blocks are involved: (although, the compiler optimizes things if possible)
    Transcript showCR:'now evaluating one of two blocks ...'.
    1 > 4 ifTrue:[
        Transcript showCR:'foo'
    ] ifFalse:[
        Transcript showCR:'bar'
    ]
here things become obvious:
    |yesBlock noBlock|

    yesBlock := [ Transcript showCR:'foo' ].
    noBlock := [ Transcript showCR:'bar' ].

    Transcript showCR:'now evaluating one of two blocks ...'.
    1 > 4 ifTrue:yesBlock
          ifFalse:noBlock
simple loops: not very objectOriented:
    |i|

    i := 1.
    [i < 10] whileTrue:[
        Transcript showCR:i.
        i := i + 1
    ]
using integer protocol:
    1 to:10 do:[:i |
        Transcript showCR:i.
    ]
interval protocol:
    (1 to:10) do:[:i |
        Transcript showCR:i.
    ]
looping over collections: bad code: (only works with numeric-indexable collections)
    |i coll|

    coll := #(9 8 7 6 5).
    i := 1.
    [i <= coll size] whileTrue:[
        Transcript showCR:(coll at:i).
        i := i + 1.
    ]
just as bad (well, marginally better ;-): (only works with numeric-indexable collections)
    |coll|

    coll := #(9 8 7 6 5).
    1 to:coll size do:[:i |
        Transcript showCR:(coll at:i).
    ]
the smalltalk way: (works with any collection)
    |coll|

    coll := #(9 8 7 6 5).
    coll do:[:element |
        Transcript showCR:element.
    ]
Rule: use enumeration protocol of the collection instead of manually indexing it. [with few exceptions] processes: forking a lightweight process (thread):
    [
        Transcript showCR:'waiting ...'.
        Delay waitForSeconds:2.
        Transcript showCR:'here I am'.
    ] fork
some with low prio:
    [
        Transcript showCR:'computing ...'.
        10000 factorial.
        Transcript showCR:'here I am'.
    ] forkAt:(Processor userBackgroundPriority)
handling exceptions:
    Error handle:[:ex |
        Transcript showCR:'exception handler forces return'.
        ex return
    ] do:[
        Transcript showCR:'now, doing something bad ...'.
        1 / 0.
        Transcript showCR:'not reached'
    ]
performing cleanup actions:
    Error handle:[:ex |
        Transcript showCR:'exception handler forces return'.
        ex return
    ] do:[
        [
            Transcript showCR:'doing something bad ...'.
            1 / 0.
            Transcript showCR:'not reached'
        ] ifCurtailed:[
            Transcript showCR:'cleanup'
        ]
    ]
delayed execution (visitor pattern): (looking carefully into the example, C/C++ programmers may raise their eyes ;-)
    |showBlock countBlock
     howMany
     top panel b1 b2|

    howMany := 0.

    showBlock := [ Transcript showCR:howMany ].
    countBlock := [ howMany := howMany + 1 ].

    top := StandardSystemView extent:200@200.
    panel := HorizontalPanelView origin:0.0@0.0 corner:1.0@1.0 in:top.

    b1 := Button label:'count up' in:panel.
    b1 action:countBlock.

    b2 := Button label:'show value' in:panel.
    b2 action:showBlock.

    top open.

    Transcript showCR:'new process started;'.
    Transcript showCR:'notice: the blocks can still access the'.
    Transcript showCR:'        howMany local variable.'.


ST/X 7.7.0.0; WebServer 1.702 at 20f6060372b9.unknown:8081; Sat, 21 Dec 2024 14:39:34 GMT