Formal model for defender method resolution

Brian Goetz brian.goetz at oracle.com
Mon Jan 31 18:19:09 PST 2011


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