Formal model for defender method resolution

David Holmes David.Holmes at
Mon Jan 31 20:31:55 PST 2011

David M. Lloyd said the following on 02/01/11 12:31:
> Honestly I don't think of this as re-abstraction.  It's the *default* 
> implementation, not *the* implementation.  You're saying, "if nobody 
> else in the hierarchy says otherwise, do this".  Especially if the 
> syntax is different.

But if you can't re-asbtract the method so that there is no default, 
subtypes can inherit an unsound default implementation. In that case the 
pattern being forced here is to always add a default even if it is:

   void m() default Util.throwNoSuchMethodError("implement me correctly")

It also means that adding a defender to a super interface exposes this 
potential danger to existing subtypes. For example if my framework uses 
a core interface Foo

   interface Foo {
     void m();

and extends it:

   interface MyFoo extends Foo {
      /** refined semantics for m() */
      void m();
     void n();
     void o();

and then has an abstract base class

   abstract class AbstractBase {
      public void n() { ... }
      public void o() { ... }
      // subclasses need to get m() right themselves

then any subclass of AbstractBase is required to implement m() or remain 
abstract. But if a defender is added to Foo.m these AbstractBase 
subclasses magically get a default implementation that is incorrect! I 
don't know about you but I'd want this flagged as an error at build time.

David Holmes

> Anyway, if someone has re-overridden a defender method it probably means 
> they did so *before* the defender method existed, and they probably 
> already have an implementation for it so it doesn't matter.  If they 
> override a defender method after the fact, they'd probably change the 
> default if they wanted to.
> That said it would be nice if one could *explicitly* remove the default 
> implementation by overriding it.  Maybe "default abstract" or something.
> On 01/31/2011 08:19 PM, 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.
>> 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>   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