martes, 24 de julio de 2007

Closures, Anonymous functions and Blocks (Part1)

A block is a chunck of code that has been delayed execution.

For example when you write:

void m( int x, int y )
{
doThis( x );
x.doThat( y );
}

Then you don't expect doThis() and doThat() to be executed immediatly but only after m() is called. This probably doesn't make sense to you if you have always compiled Java, because in compiled languages there is one extra step: compiling with javac and the invoking the program (with java). But imagine you are writing code in an IDE that executes your code so that if you write main(...) it executes main, but if you write void main(...) { ... } you are simply defining main and therefore at the end of the definition the IDE says: "main defined for class XXX".

If you understand this, then you know exactly what a block is in Smalltalk. In Smalltalk blocks are a way to write delayed evaluation, for example if you execute:

a doThis: x with: y

You are seding the message: "#doThis:with:" (ignore the "" they were added by me to complicate things, and ignore # for the moment) and the parameters are x and y in that order.

The equivalent in Java would be:

a.doThisWith( x, y );

The thing is that Smalltalk may execute that immediatly (if instructed to). For the curious who still do not get Smalltalk 80 IDE's, you have to select with mouse the text to evaluate and then right click with the mouse so that the context menu appears and then select either printIt or executeIt, depending on what you cant to do. That is a programming interface from 1980 and still in 2007 some people don't get it.

So we can imagine in Java an IDE that let us evaluate code. I mean, some debuggers allow us to do this already, so this is not so farfetched. Altough let me explain to the Smalltalk naysayers and to be aficionados that in Smalltalk the program is always running, meaning that if you want to take the program down, you have to take down the IDE too.

So in Smalltalk I can write code so that the IDE doesn't execute immediatly. That magic is called a block and it is used like this:

[a doThis: x with: y]

When I evaluate it I get nothing and when I print it I get "a Block".

Smalltalk uses these blocks as tools to build control structures (like if, while, etc.) that Smalltalk does not have.

aBoolean ifTrue: [ b doThat: y + x ] if False: [a doThis: x with: y].

The Java equivalent would be:

if ( aBoolean )
{
b.doThat( y + x );
}
else {
a.doThisWith( x, y );
}

So the [] in Smalltalk are the equivalent of {} in Java.

Ok, guys and gals, you can go away now, there is nothing to be seen here.

Still here? Ok, there are some differences. Blocks in Smalltalk can take parameters:

aList do: [ :elem | elem doSomething ]

which would be the equivalent of:

for ( Iterator it = aList.iterator(); it.hasNext(); )
{
Elem elem = it.next();
elem.doSomething();
}

The thing is that the block in Smalltalk is a First Class Object, or an object of the first kind, granted all privileges of full objects, which means that it can be assigned to variables, passed to functions and returned from functions, which is to say, it can be assigned to variables and the language is not weird, so:

block1 := [ :elem | elem doSomething ].
aList do: block1.

Coolisimo! But there is more.

Did I mention that Smalltalk has no control of execution? Then how does Smalltalk do while loops?

[condition] whileTrue: aBlock.

condition should be any boolean variable or boolean expression while aBlock could be any block. Please notice that the receiver of #whileTrue: is a block. Why?

Because the condition has to be tested after every completion of the cycle in the loop. If it were not written as a block, it would be executed once and then it would either never execute the loop or never exit the loop.

This means the control structures in Smalltalk are not implemented built-in the language and that you can create new control structures, like switch/cases and the like. This of course is not the same in Java, because in Java the blocks are not first class citizens and the control structures are therefore built-in the compiler and the JVM.

How is aList>>do: implemented?

"let us suppose that the list has a first node and then each node has a next node"
do: aBlock
| currentNode |
aBlock value: node.
currentNode := node.
[ currentNode next isNull not ] whileTrue: [ aBlock value: node.
currentNode := node. ]

Comments in Smalltalk are surrounded by: "" and variable declarations can occur only at the top of any method using pipes: | aVar | declares aVar as an untyped variable because in Smalltalk all variables are untyped.

Enough of Smalltalk already, can we do that in Java?

Block block1 = Block #void#( Elem elem ) {
elem.doSomething();
};
aList.forEach( block1 );

Please notice that I wrote nothing strange except for the assigment. If I can get the assigment to work, then passing a block as parameter and returning a block would all be logical conclusions, so let as concentrate on the assignment.

Java has something similar to this called anonymous classes, so that for example you can write delayed execution using Runnables:

Runnable delexec = new Runnable() {
public void run() {
System.out.println( "hello" );
}
};
delexec.run();

So Java has a mechanism to simulate and emulate blocks, but the syntax needs a lot of sugar.

Also Runnables are ok when you don't need parameters, but if you need parameters, you should declare your own interfaces and you would have endless interface pollution. Even if you just pass Object, you would still need:

public interface Executable
{
void run();
void runOn( Object ob1 );
void runOn( Object ob1, Object ob2 );
void runOn( Object ob1, Object ob2, Object ob3 );
void runOnAll( Object [] obArr );
}

The problem with this solution is that you would need to define all the methods, even if you just needed one.

So imagine Runnable when needing no parameters (run()), then Runnable1 when needing 1 parameter (runOn(Object ob1)), Runnable2 when needing 2 parameters (runOn(Object ob1, Object ob2)), etc.

Closures are any block of code that has no free variables. A free variable is a variable that is not assigned any value (yet), so that it can take any value passed as parameter (that seems to be the definition of a block any way).

1 comentario:

Neal Gafter dijo...

Java does not have closures/blocks like Smalltalk. Yet.

See http://www.javac.info/