In this session, I'll introduce blocks.
They're sort of anonymous methods also called lexical closures.
They're everywhere in Pharo.
They're the base of loops, conditionals, iterators,
and even GUIs or dedicated languages.
They're at the heart of the system.
They've only been introduced in the latest version of Java.
To define a block, use square brackets.
This an example:
[expressions...]
We'll talk about block definition.
Another example:
this expression, 1/0,
returns an error when executed.
Let's encapsulate it in a block
by defining a block that contains the expression 1/0.
If I evaluate this block's definition, nothing happens: no error.
It returns the block
as a block definition doesn't execute its body.
You can define as many blocks as you wish:
the expressions in its body are frozen.
To evaluate a block and the expressions in its body,
you must do it explicitly through the message value.
For instance, this is a block: [2 + 6]
You send it the message value.
The expressions in the body are evaluated.
It returns the result, 8.
However, if the block contains erroneous expressions,
the error is returned when the block is evaluated,
as in the example 2.
[1/0]: I send the message value to the block.
It returns an error.
Blocks can also take arguments
as in this argument. It's just like methods.
A block is always opened by [
and closed by ].
All the arguments are prefixed by a colon.
Then there's |, a pipe.
It separates the argument declaration from the block's body,
the expressions it contains.
The argument in this example is x.
x + 2 is the only expression in the block.
If I send the message value to the block,
you have to use a specific message, value: with a parameter.
At the same time, you pass the value 5 which replaces the argument x
when the expressions of the block are evaluated.
If I send the message value: 5 to this block,
it returns 7
since the value of x is 5 when the block is evaluated.
This is like my previous example,
but with several expressions in the block.
I have two here: x+33 and x+2.
When I send value: 5
to evaluate the expressions in the block,
the evaluation returns
only the value of the last expression in the block.
It only returns the result of x+2,
7.
Blocks are normal objects in Pharo.
They can be stored in temporary variables.
They can be sent messages like normal objects.
This is the example I have for you here.
You can store the definition of this block, x+2,
in a variable called add2.
Then you send messages to evaluate the block several times.
I send the message value: once
by telling it to evaluate itself with the value 5: it returns 7.
Then the message value: 33.
It returns 35.
You can also define blocks with several arguments.
For instance, x and y. This block has two arguments.
But how would you evaluate this block
since you need to pass two values to trigger its evaluation,
5 and 7 which would replace x and y?
The answer is that you use the message value: value:,
a method of the class block.
5 replaces x and 7 replaces y.
It returns 12.
Like methods, blocks can also define temporary variables.
This example is an actual example:
it comes from the class Collection.
The block starts here. It ends there.
It takes one argument called :index.
It takes one temporary variable defined here between two |.
It's called args.
This temporary variable args
exists only during the evaluation of the expressions in the block.
Blocks are defined in methods.
In a block, you can also use a return.
This is an example from the class Integer.
The method is called factorial.
There are several blocks in the method.
These blocks contain returns, or ^.
The return helps to exit the method factorial.
For instance, if I send the message factorial to the integer 0,
it returns the answer 1.
I get this answer thanks to this ^, the first in the block,
which helps to exit the method factorial.
A return in a block helps to exit the method
which defines the block.
A piece of advice for when you use blocks:
blocks are extremely powerful elements.
You must use them carefully.
Don't go beyond two to three arguments for one block.
If you have more, it becomes incomprehensible.
It's better to define a class with instance variables and methods:
it'll be much more legible.
In the course, we studied blocks, their syntax,
the fact they were some sort of anonymous methods,
that is, lexical closures;
they can be stored in variables as they're like any other object.
In other lessons, we'll see that blocks are the basis of many constructions
such as loops, iterations, etc.