Formal model for defender method resolution

Ali Ebrahimi ali.ebrahimi1781 at gmail.com
Tue Feb 1 02:07:57 PST 2011


+1

On Tue, Feb 1, 2011 at 11:35 AM, Peter Levart <peter.levart at marand.si>wrote:

> 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