How shall we write this Scheme code in Java?
(define (foo n) (lambda (i) (set! n (+ n i)) n))
Foo creates and returns a program for generating a number sequence. Conceptually, n represents a running total and i represesnts an increment. foo's integer argument is the initial running total; foo initializes (injects) this into the the procedure it creates and returns.
(define x (foo 100))
x ==> (lambda (i)
(set! n (+ n i)) )
(x 3)
(x 10)
(define y (foo 50))
(y 3)
(y 10)
(x 5)
(y 5)
Each call to x adds something to n, while updating (i.e., mutating) n, and returns the the new running total. The closure foo creates captures the parameter n, forever.
Notice that the state of the variable, n, gets captured by the definition of the lambda expression. The Scheme procedure, foo, "remembers" foo's argument n, and "remembers" the updated value stored in n each time the lambda expression is executed. Scheme differs from other statically scoped language, like Java, because it is able to "remember" variables that in other languages would have been out of scope.
How do we do this in an OO language, like C++, Java, or Smalltalk? Especially since other OO languages may not support closures.
First, let's consider C++, which has no support for closures. We have to use object state, instead. Use a class to define a member field, n. Members lifetimes are associated with the object's lifetime, so everything works fine.
class foo {
int n;
public:
foo (int m) { n = m; }
int operator() (int i) { n += i; return n; }
};
Using OO the constructor "captures" the value for n in the object (instance's) state. This C++ example uses an object "to simulate a closure".
This would be called as follows:
foo x(100); cout << x(3); cout << x(10); foo y(50); cout << y(3); cout << y(10); cout << x(5); cout << y(5);
> Or in Java, there are two ways. First we could do the syntactic-sugar equivalent of C++.:
public class foo {
private int n;
public foo(int n) {
this.n = n;
}
public int inc(int i) {
n += i; return n;
}
}
...
foo x = new foo(100);
System.err.prtinln(x.inc(3));
System.err.prtinln(x.inc(2));
foo y = new foo(50);
System.err.prtinln(y.inc(3));
System.err.prtinln(y.inc(10));
System.err.prtinln(x.inc(5));
System.err.prtinln(y.inc(5));
Notice that we connot overload operator(), so define a method, inc, instead.
The second way to do this in Java is with anonymous inner classes: Java's (anonymous) inner class provides the potential for a closure-like construct:
interface Incrementor {
int inc (int i);
};
...
class foo
static public Incrementor gen( final int n ) {
return new Incrementor() {
public int inc( int i ) {
n = n + i; // one big prob is here
return n;
}
};
}
}
Assuming a class named foo,
Incrementor x = foo.gen(100); f.inc(3); f.inc(2);
This eliminates the need for an instance variable, making use of the closure-like behaviour of inner classes in Java. ONE BIG PROBLEM: it's illegal, because cannot assign to the final variable, n. Note some implementations for Java VM's would support closures, e.g., IBM jikes, could support this without problem, the compile could generate correct bytecodes and the VM could evaluate, but the JLS deems this an error.