Exception transparency

Neal Gafter neal at gafter.com
Thu Jun 10 16:25:37 PDT 2010


Rémi-

I agree.  I mean, I don't care whether or not you have to explain it (;-),
but I think both //1 and //2 should be treated as throwing checked exception
types A|B (not their lub()), even though that would be a change from the
current behavior.

In theory, this is not backward compatible, because the following program,
which is specified as legal today, would become illegal under the change.
But due to a previously unreported compiler bug (I'm using javac version
1.6.0_07), it won't compile anyway.  I'll be surprised if anyone can find
production code that compiles today and would break under a hypothetical
change to lub() for all type parameters that extend Throwable or a subtype.

*interface I {}
class Common extends Exception {}
class A extends Common implements I {}
class B extends Common implements I {}
public class Main {
    static <E extends Exception> E choose(E e1, E e2) {
        return (Math.random() < 0.5) ? e1 : e2;
    }
    public static void main(String[] args) {
        try {
            throw choose(new A(), new B());
        } catch (A a) { // SE 6 error (due to compiler bug)
        } catch (B a) {
        } catch (Common a) { // proposed SE 7 error: no uncaught Common
thrown
        }
    }
}
*

Cheers,
Neal

On Thu, Jun 10, 2010 at 3:50 PM, Rémi Forax <forax at univ-mlv.fr> wrote:

> Le 10/06/2010 23:48, Alex Buckley a écrit :
> > I believe the short answer to this is "yes".
> >
> > Alex
> >
>
> Please, I don't want to explain why //1 and //2 aren't equivalent.
>
> class Test {
>   static<E extends Exception>  E test(E e1, E e2) {
>     return (Math.random()<  0.5)? e1: e2;
>   }
>
>
>   static<E extends Exception>  void test(E e1, E e2) throws E {
>     throw (Math.random()<  0.5)? e1: e2;
>   }
>
>   public void main(String[] args) {
>     throw test1(new A(), new B());   //1
>
>     test2(new A(), new B());  //2
>   }
> }
>
> Rémi
>
>
> > On 6/10/2010 2:41 PM, Peter Levart wrote:
> >
> >> Hello Maurizio,
> >>
> >> What if compiler would track internally any type variable with Throwable
> bound in such a way
> >> that when used in any context except "throw" statement it would mean
> lub(X,Y,Z,...) as defined
> >> today but when used in throw statement it would mean X|Y|Z|...
> >>
> >> class Foo<X>  { void set(X x) {} }
> >>
> >> class A extends Exception {}
> >>
> >> class B extends Exception {}
> >>
> >> class Test {
> >>
> >>    static<E extends Exception>  Foo<E>  test(E e1, E e2) throws E {
> >>      switch (new Random().nextInt(3)) {
> >>        case 0: throw e1;
> >>        case 1: throw e2;
> >>        default: return new Foo<E>();
> >>      }
> >>    }
> >>
> >>    public static void main(String args) {
> >>      try {
> >>        test(new A(), new B()).set(new Exception());
> >>      }
> >>      catch (A a) {}
> >>      catch (B b) {}
> >>    }
> >>
> >> }
> >>
> >>
> >> Would that work? Would that be back compatible?
> >>
> >> Regards, Peter
> >>
> >>
> >> On Tuesday, June 08, 2010 02:25:40 pm Maurizio Cimadamore wrote:
> >>
> >>> On 08/06/10 13:13, Maurizio Cimadamore wrote:
> >>>
> >>>> On 08/06/10 12:54, Peter Levart wrote:
> >>>>
> >>>>> On 06/08/10, Maurizio Cimadamore wrote:
> >>>>>
> >>>>>>>> needs to guess any intentions where it will affect realistic code.
> >>>>>>>>
> >>>>>>> Neal,
> >>>>>>> I have trouble to figure out an example of such rare places.
> >>>>>>>
> >>>>>>> Do you have an example of such code ?
> >>>>>>>
> >>>>>> Could be this?
> >>>>>>
> >>>>>> class A<X>    extends Exception {}
> >>>>>> class B extends A<String>    {}
> >>>>>> class C extends A<Integer>    {}
> >>>>>>
> >>>>>> <throws E>    E choose(E e1, E e2) { ... }
> >>>>>>
> >>>>>> choose(new B(), new C()); //what is the inferred type for E???
> >>>>>>
> >>>>>> In JDK 5/6 E is inferred to be A<? extends Object&    Comparable<?
> >>>>>> extends Object&    Comparable<?>>>. In JDK 7 with the proposed new
> >>>>>> semantics for 'exception-bound' type-vars the inferred type would be
> >>>>>> something like A<String>    | A<Integer>, which, I guess, would need
> to
> >>>>>> be rejected as an ill-formed type on the grounds of
> type-disjointness
> >>>>>> (A<String>    and A<Integer>    are not provably distinct).
> >>>>>>
> >>>>> Are you suggesting to relax the rule that generic classes can not
> extend
> >>>>> Throwable?
> >>>>>
> >>>> Good catch - my example is illegal; no incompatibility here.
> >>>>
> >>> I tried harder ;-) :
> >>>
> >>> class Foo<X>  { void set(X x) {} }
> >>>
> >>> class A extends Exception {}
> >>> class B extends Exception {}
> >>>
> >>> class Test {
> >>>      static<E extends Exception>  Foo<E>  test(E e1, E e2){ return new
> >>> Foo<E>(); }
> >>>
> >>>      public static void main(String args) {
> >>>         test(new A(), new B()).set(new Exception());
> >>>      }
> >>> }
> >>>
> >>> This compiles in JDK 5/6 (E inferred to be Exception); it fails to
> >>> compile under JDK 7 if we assume that type-variables with Exception
> >>> bound have a 'varadic' semantics; in fact in this case the type A|B
> >>> would be inferred. But this means that you cannot pass an Exception
> >>> where an A|B is expected.
> >>>
> >>> Maurizio
> >>>
> >>>
> >>>> Maurizio
> >>>>
> >>>>
> >>>>> Peter
> >>>>>
> >>>>>
> >>>>>> Maurizio
> >>>>>>
> >>
> >
>
>
>


More information about the lambda-dev mailing list