Formal model for defender method resolution

Peter Levart peter.levart at marand.si
Tue Feb 1 00:05:51 PST 2011


On 02/01/11, Brian Goetz wrote:
> All things being equal, I would agree with (1) and (3).  Unfortunately 
> reabstraction of defended methods seems to complicate resolution, and 
> given that people use reabstraction fairly infrequently now, it may be a 
> better choice to accept some additional apparent inconsistency in 
> exchange for simpler semantics.
> 
> I am not sure I agree with (2), because it is not uncommon to see an 
> overriding purely to add a note to the Javadoc, enough so that 
> supporting reabstraction "breaks" the common intuition that 
> (non-covariantly) overriding a method in an interface is a no-op.

So what we have here is two distinct desirable semantics for an interface method that overrides a method in a superinterface:

a) re-abstraction (that discards any default definition in a supertype)
b) re-declaration (that inherits any default definition from a supertype)

These two semantics can both be supported, followed by two distinct syntaxes:

interface A {
  Object m() default Defaults.m;
}

interface B  extends A {
  Object m(); // re-abstraction
}

interface C extends A {
  Object m() default; // re-declaration which inherits default from A
}

interface CovariantB extends A {
  String m(); // re-abstraction with covariant return (OK)
}

interface CovariantC extends A {
  String m() default; // ILLEGAL! can not inherit default when using covariant return
}

... so inheriting default from super should be explicitly requested since it defines a contract that any (or none) possible default from a supertype is ok (for example those methods that override just to add javadoc comments). This should fail at compile time if the overriding method uses a covariant return (regardless of the compatibility of the default method implementation, since it can change).


Peter

> 
> 
> 
> On 1/31/2011 8:56 PM, Howard Lovatt wrote:
> > Hi,
> >
> > I think it is best that a defended method can be re-abstracted (like
> > abstract classes currently do) for three reasons:
> >
> > 1. It is the expected behaviour. If you see "m();" in an interface,
> > you expect it to be abstract and you expect to have to implement it.
> > You should not be required to check the hierarchy to see if it is
> > inheriting something unexpected. If you forget to implement the method
> > you won't be warned, silently and potentially insidiously a default
> > will appear.
> >
> > 2. It is the only safe assumption. If someone is overriding a defended
> > method then they are doing so for some good reason. Commonly, the
> > semantics of the method are subtly altered and a modification to the
> > Javadoc is required to note the change. The fact that the semantics
> > have changed means that inheriting the method isn't safe and therefore
> > it should be re-abstracted.
> >
> > 3. It is important to be consistant with abstract classes, since
> > defender methods are similar to abstract classes and it will be
> > confusing if they behave differently. People may well start to use
> > defender methods were they previously used abstract classes, therefore
> > the two should be as interchangeable as possible.
> >
> > Cheers,
> >
> >   -- Howard.
> >
> > On 29 January 2011 13:03, David Holmes<David.Holmes at oracle.com>  wrote:
> >> Alex,
> >>
> >>   >  Again, why do defenders if defending a method in a top superinterface
> >>   >  is going to be undone by "accidental" overriding (by rather hopeless
> >>   >  abstract methods) in subinterfaces?
> >>
> >> Let's not forget that the primary use-case for defenders is to allow us
> >> to add _new_ methods to interfaces together with an implementation so
> >> that (most) existing classes will continue to compile and execute
> >> correctly. Adding defenders to existing methods is not the primary
> >> use-case and as per past discussions is somewhat perilous.
> >>
> >> The crux of this matter is "accidental overriding" versus "deliberate
> >> overriding". If I override an interface method f() in B to specialize it
> >> compared to how it is defined in A then not only do I not want to
> >> inherit A's defender for f(), it would be inherently incorrect to do so
> >> because it does not implement the correct semantics.
> >>
> >> You seem to want to cater for the programmer who accidentally overrides
> >> f() (to tweak javadoc in a semantically non-changing way) to still get a
> >> defender that exists somewhere in the inheritance hierarchy. Whereas I
> >> (and I think others) expect overriding (with no explicit defender) to
> >> mean reabstraction of the method.
> >>
> >> Why are you against reabstraction? Reabstraction is always safe, if not
> >> always convenient. Silent inheritance may be convenient for some but is
> >> potentially unsafe.
> >>
> >> Why should the addition of a defender in a super interface break my
> >> framework by allowing subclasses to silently inherit use of a defender
> >> that doesn't implement the semantics of the current type?
> >>
> >> David Holmes
> >>
> >> Alex Buckley said the following on 01/29/11 11:06:
> >>> On 1/28/2011 3:55 PM, Neal Gafter wrote:
> >>>> Die due to no f impl, exactly as it does today.  In this case it is
> >>>> irrelevant that one of the newly added methods has a default, as that
> >>>> default could not possibly be the one that the call resolves to.  This
> >>>> is a situation that occurs today and that is indeed what happens.
> >>>
> >>> Why bother with defenders if a call to a defended method (and I think
> >>> C.f _is_ defended by A.f, despite B.f) is going to die at runtime?
> >>>
> >>> Not sure what you mean by "that default could not possibly be the one
> >>> that the call resolves to." The caller who causes execution of
> >>> invokeinterface B.f()B; has no idea whether the receiver class
> >>> implements f via a defender or via declaration/class inheritance.
> >>>
> >>>>      If there's no error for B, and B.f _does_ inherit A.f's default, then
> >>>>      invokeinterface B.f()B on a C may return an A that's not a B, and we
> >>>>      definitely have unsoundness.
> >>>>
> >>>> Agreed!  Which is why B.f should not inherit A.f's default.
> >>>>
> >>>>
> >>>>      So either there should be an error on B;
> >>>>
> >>>>
> >>>> Huh?  Why?  This is a simple case of reabstraction.  There's nothing
> >>>> wrong with B.  There might or might not be something wrong with some
> >>>> further derived type, but B is fine.
> >>>
> >>> It's not reabstraction if A.f is given a defender after B gains f.
> >>> Defending the highest superinterface alone seems like a common migration
> >>> path, one we should support.
> >>>
> >>>>      or no error yet _B.f inherits
> >>>>      A.f's default and the inherited defender is typechecked in its new
> >>>>      environment_.
> >>>>
> >>>> Huh?  Why?  When you reabstract a method, it has no implementation to
> >>>> inherit or check.
> >>>
> >>> Again, why do defenders if defending a method in a top superinterface is
> >>> going to be undone by "accidental" overriding (by rather hopeless
> >>> abstract methods) in subinterfaces?
> >>>
> >>> Alex
> >>>
> >>
> >>
> >
> >
> >
> 
> 


More information about the lambda-dev mailing list