Completion Transparency
Completion transparency enables us to create methods that transparently return the result of a closure which is passed as argument. For example:
static <T> T withLock(Lock lock, { => T } block) {
lock.lock();
try {
return block.invoke();
} finally {
lock.unlock();
}
}
We can pass to the withLock method a block that returns any value. For example:
Lock lock = new ReentrantLock();
Integer i = withLock(lock, { => Integer.valueOf(42) });
Due to completion transparency, we can also use a block that does not return anything (i.e. a block of type { => void }):
withLock(lock, { => System.out.println("mining..."); });
And even a block that cannot complete normally, i.e. throws exception (in this case only unchecked exceptions are allowed):
withLock(lock, { => throw new NullPointerException(); });
To allow checked exceptions as well, we can use exceptions transparency:
static <T, throws E> T withLockEx(Lock lock, { => T throws E} block)
throws E {
lock.lock();
try {
return block.invoke();
} finally {
lock.unlock();
}
}
public static void main(String[] args) {
try {
Lock lock = new ReentrantLock();
withLockEx(lock, { => throw new Exception(); });
} catch (Exception e) { e.printStackTrace(); }
}
Implementation issue
Let us recall that each closure is converted to an instance of interface. For example, a closure
{ => System.out.println("buff"); } is converted to an instance of V:
public interface V {
void invoke();
}
To achieve completion transparency, the compiler is allowed to use Void instead of void.
For example, the code
withLock(lock, { => System.out.println("miaow"); });
will be transformed approximately as follows:
withLock(lock, new javax.lang.function.O() {
public Void invoke() {
System.out.println("miaow");
return null;
}
}
In case of closures that do not complete normally, the invoke method returns java.lang.Unreachable
which is a special class that is considered a subclass of all classes.
This means that an Unreachable may be assigned to any reference variable.
For example, the statement
Integer i = { => throw new NullPointerException(); }.invoke();
will be transformed roughly as follows:
Integer i = new javax.lang.function.O() {
public Unreachable invoke() { throw new NullPointerException(); }
}.invoke();

No comments:
Post a Comment