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