Formal model for defender method resolution
howard.lovatt at gmail.com
Mon Jan 31 17:56:09 PST 2011
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
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.
On 29 January 2011 13:03, David Holmes <David.Holmes at oracle.com> wrote:
> > 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
>>> 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?
More information about the lambda-dev