Formal model for defender method resolution

Howard Lovatt howard.lovatt at
Mon Jan 31 20:53:43 PST 2011


Comments in line

On 1 February 2011 13:31, David M. Lloyd <david.lloyd at> wrote:
> 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.

I think the same about *any* method body, unless final, it is just the
*default* that I am inheriting not *the* implementation. Hence the
argument for the same behaviour as any other class hierarchy.

This also raises the question of if final should be allowed for a
method with a default?

> 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.

These arguments are neutral for if the method is re-abstracted or not.
However another scenario, which I think will be common, is the default
is added to an existing method of a library that you use. You have no
way of anticipating this and it will not be obvious it has happened
(without trawling the Javadoc for all the methods in a library - who
does that for each release!).

Lets make this a concrete example, in List there is an add method and
out of the goodness of their heart Oracle add a default to it
(AbstractList already has one). Now in my version of List,
NonNullList, I inherit List but override add noting that you can't add
nulls to this list. I now write a new implementation of NonNullList
and mean to override add but I forget. As things stand now the
compiler tells me that I haven't overridden add. However if the
default comes through past my override, then the compiler no longer
warns me and I have a difficult to find bug.

I think this type of bug may well happen since people won't track
third party API's, even java.util ones, that closely and may be
completely unaware that they now have a default.

> That said it would be nice if one could *explicitly* remove the default
> implementation by overriding it.  Maybe "default abstract" or something.

How about the other way round:

Object m(); // means re-abstract (assuming it has a default, if it
doesn't then it is still abstract - no error)

Object m() default super; // means inherit the super method even
though I have redefined the method (error if no super default or more
than one super default exists)

Object m() default A.super; // means explicitly inherit the default
from super interface A (error if A isn't a super interface or if m
doesn't have a default in A)

 -- Howard.

> 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
> --
> - DML

More information about the lambda-dev mailing list