Nonlocal transfer
In unrestricted closures, we can use the break
, continue
, and
return
statements.
for (int i = 0; i < 5; i++) {
System.out.println(i);
if (i == 2) { ==> break; }.invoke();
}
These statements are always lexically bound, i.e. they are bound in the context in which
the closure is declared (as opposite to invoked). So, the following code will print numbers
from <1,10> that are not multiples of 3.
static void m(int i, { int => boolean } cond, { ==> void } block) {
if (cond.invoke(i)) {
block.invoke();
}
}
public static void main(String[] args) {
for (int i = 1; i < 10; i++) {
// continue is bound to the for loop
m(i, { int i => i % 3 == 0 }, { ==> continue; });
System.out.println(i);
}
}
The return
statement returns from the bound method.
static int m1() {
// return here means "return from m1"
m2({ double d ==> if (d < 0.5) return 1; });
return 0;
}
static void m2({ double ==> void } p) {
// the closure invocation can cause return from m1
p.invoke(Math.random());
}
If the bound method is not active at the time when we call the closure with the return
statement, we will get the UnmatchedTransfer exception. For example:
// any type can be used as the return type of p in this
// example because the closure always returns earlier
// so, p can be declared also as static { ==> int } p;
static { ==> boolean } p;
static int m1() {
p = { ==> return 1; };
return 0;
}
public static void main(String[] args) {
System.out.println(m1());
System.out.println(p.invoke());
}
Unrestricted closures are useful when declaring "statement-like" methods.
static void withLock(Lock lock, { ==> void } block) {
try {
lock.lock();
block.invoke();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
Lock guard = new ReentrantLock();
double d = Math.random();
withLock(guard) {
if (d < 0.5) {
return;
}
...
}
}