Exception transparency
Daniel Yokomizo
daniel.yokomizo at gmail.com
Tue Jun 8 01:08:15 PDT 2010
Reinier,
On Tue, Jun 8, 2010 at 1:53 AM, Reinier Zwitserloot
<reinier at zwitserloot.com> wrote:
> Making the exceptions transparent by encoding them in the type system is
> going to be very unwieldy, even if a "throws T" variadic type parameter
> concept is introduced. I've got a much better idea: Escape detection on
> closures. Any closures that are guaranteed to run such that the runtime
> stack matches the lexical stack can get exception transparency completely
> free, no new syntax and no new concepts required; it would "just work".
>
> Let's take Comparator for example. Currently it is used in two contexts;
> Collections/Arrays.sort, as well as for the TreeSet constructor. It would
> make perfect sense for the sort variant to use the proposed variadic type
> parameter concept to make any exceptions thrown as part of the comparison
> transparent. Side-stepping for a moment the general shambles that occurs
> when trying to integrate functional types into existing library code, this
> would perhaps look something like so:
>
> public static <T, throws E> void sort(List<T> a, Comparator<? super T, E> c)
> throws E {
> ...
> }
>
> Just look at that. Generics in libraries already has a tendency to look like
> gobbledygook and the above is not helping things at all. Even if we abandon
> Comparator here and use a straight closure type like so:
>
> public static <T, throws E> void sort(List<T> a, #int(T, T)(throws E) c)
> throws E {
> ...
> }
>
> isn't an improvement.
>
>
> But, let's stick with it, and inspect what happens to TreeSet.
>
> Now we run into even bigger trouble; applying a (variadic or monadic,
> doesn't matter) exceptions type parameter here is simply not possible. We'd
> have to add "throws E" to at the very least TreeSet's add and addAll
> methods, but we clearly can't; both of those methods come from the Set
> interface and those don't have any thrown exceptions declared today, so,
> that won't work. Even in a hypothetical world where we can break backwards
> compatibility we still can't pragmatically replace Set's current add method
> with: "public boolean add(T item) throws E" - because what's that E even
> stand for? In e.g. a HashSet, and most other sets, that "E" makes no sense
> at all. Its a unique aspect of TreeSet. We could simply not let TreeSet
> implement Set but that feels completely wrong.
>
>
> The most obvious solution then appears to be one of three options:
>
> (A) don't try; leave sort and TreeSet untouched and do not add exception
> transparency to sort. But that would be a shame.
> (B) overload Collections.sort with the variadic type parameter based
> exception transparency. Leave TreeSet untouched. But now we have two
> incompatible "comparator" concepts, so this too would be a weak solution.
> (C) hack it together by letting TreeSet rewrap any checked exceptions thrown
> during add/addAll into a custom unchecked class, akin to
> InvocationTargetException or ExecutionException). But that's the very
> ugliness we're trying to avoid!
[snip]
Actually, assuming this change in Comparator, TreeSet constructor
could have this signature:
TreeSet(Comparator<? super T, throws void>)
It's only necessary to have this equivalence/subtyping rules (AFAICS):
<X extends RuntimeException> throws X ~ throws void
<X extends Error> throws X ~ throws void
I'm actually concerned about composing such signatures. For example,
if we have a Function type with a possible exception:
interface Function<F,G, throws X> {
public G apply(F f) throws X;
}
It should be possible to write a safe compose:
<F, G, H, throws X, throws Y> Function<F, H, throws X | Y>
compose(Function<F, G, X> fg, Function<? super G, H, Y> gh);
And store the composed function in a variable. For this to work we
need to have disjunctive type as a first class citizen (as Peter
pointed in a previous message).
I have such needs in production code today (i.e. composable exception
transparency and first class disjunctive types), for a problem that is
more complex than just functions that can be composed (but would use
the same solution), so in my situation any solution without first
class support for composition wouldn't match my needs.
Best regards,
Daniel Yokomizo
More information about the lambda-dev
mailing list