Re-specification and re-abstraction

Howard Lovatt howard.lovatt at gmail.com
Thu Dec 22 15:35:25 PST 2011


Brian,

This is in response to your private note - thanks.

As a side note I have read your paper but can't say I fully understand all
the implications and therefore find examples, enumerations, useful.

You make a good point re multiple inheritance, is the following enumeration
an improvement (diamond inheritance):

interface T { void m(); } // Top of the diamonds
interface L extends T { void m() { ... } } // L defines a default
interface R extends T { void m() { ... } } // R defines a default
interface B0 extends L, R {} // No-op, in this example effectively:
re-abstract & no Javadoc
interface B1 extends L, R { void m(); } // Re-abstract & Javadoc
interface B2L extends L, R { void m() { L.super.m(); } } // Re-use L &
Javadoc
interface B2R extends L, R { void m() { R.super.m(); } } // Re-use R &
Javadoc
interface B3 extends L, R { void m() { ... } } // Re-define & Javadoc

As you said this is a choice of lesser evils, some people will not like a
Javdoc comment causing a re-abstraction.

I can't speak for others but suspect their point of view is similar to mine
which is I don't want to undermine your work, to me it is great that Java
is moving forward. To this end I have only sent this to you and will drop
out of commenting on the thread since you don't seem to find the discussion
helpful.

Merry Christmas,

 -- Howard.

On 23 December 2011 09:41, Brian Goetz <brian.goetz at oracle.com> wrote:

> In your "enumeration" of the forms, you've conveniently ignored most of
> the inherent complexity of the feature -- all your examples involve
> strictly single inheritance!  I don't think you have nearly enough on the
> table yet to describe it as a solution, let alone a "pleasingly simple" one.
>
> On 12/22/2011 5:31 PM, Howard Lovatt wrote:
>
>> David H and Peter L make a good point about potentially surprising
>> behaviour and introducing difficult to find bugs with inherited defender
>> methods and on balance I favour their suggested semantics over the
>> current semantics. It is also a pleasingly simple solution with five
>> easy to follow forms:
>>
>> interface M0 { void m() { ... } } // m has a default body and Javadoc
>> interface M1 extends M0 { void m(); } // m is re-abstracted & Javadoc
>> interface M2 extends M0 { void m() { M0.super.m(); } } // Re-use M0's
>> definition & Javadoc
>> interface M3 extends M0 {} // Re-use M0's definition, no Javadoc
>> interface M4 extends M0 { void m() { ... } } // Re-define m & Javadoc
>>
>> I do accept that the current semantics have some advantage and also that
>> either set of semantics are workable, however I slightly prefer the
>> above semantics. Partially that preference is because I find "default"
>> and "default none" ugly, but the biggest point is that I think it will
>> least likely to cause difficult to find bugs.
>>
>>  -- Howard.
>>
>> On 23 December 2011 01:14, Brian Goetz <brian.goetz at oracle.com
>> <mailto:brian.goetz at oracle.com**>> wrote:
>>
>>    The tension here is between respecting the existing language behavior,
>>    intended or not -- where exact redeclarations of interface methods is a
>>    no-op -- and how we want this "new" feature to work, and who loses when
>>    existing usage patterns conflict with the desired usage patterns for
>> the
>>    new feature.
>>
>>    The existing semantics were designed to respect the no-op-ness of these
>>    redeclarations, effectively making them "invisible" to the default
>>    calculation, rather than give a potentially surprising new meaning to a
>>    hitherto meaningless (but used in practice) construct.
>>
>>    Neither answer is obviously right, or even good (and anyone claiming
>>    otherwise has not thought through it enough.)  Its only a matter of
>>    which alternative is less bad, and there's arguments on both sides.  We
>>    went back and forth on this one a few times already, and may well go
>>    back and forth on it a few times more before we're done.
>>
>>
>>    On 12/22/2011 2:25 AM, Peter Levart wrote:
>>     > On 12/22/11, David Holmes wrote:
>>     >> One of the things that concerns me in the current State of the
>>    Lambda is
>>     >> the fact that re-specification of method on a sub-interface does
>> not
>>     >> re-abstract the method, but continues to allow any default from
>>    a super
>>     >> interface to be applied to that method. This is inherently wrong
>>    in my
>>     >> opinion.
>>     >>
>>     >> Consider this fictitious but plausible example.
>>     >>
>>     >> We have the present Map interface. We also have a ConcurrentMap
>>     >> interface that adds some additional methods that provide
>>    atomicity for
>>     >> compound actions on maps that support concurrent access.
>>     >>
>>     >> Suppose that ConcurrentMap actually re-specified each of the Map
>>    methods
>>     >> to add various thread-safety and atomicity guarantees.
>>     >>
>>     >> Now suppose that the maintainer of Map decides to take advantage of
>>     >> default methods and adds default implementations to some of
>>    those Map
>>     >> methods. This is not done with ConcurrentMap in mind and those
>>     >> implementations offer no specific thread-safety or atomicity
>>    guarantees.
>>     >> It should be obvious that those implementations are not likely to
>> be
>>     >> valid for any class that implements ConcurrentMap.
>>     >>
>>     >> Given the current semantics however, if I were to write a class
>> that
>>     >> implements ConcurrentMap and accidentally forgot to implement those
>>     >> methods for which a default exists in Map, then my class will in
>>    fact
>>     >> "inherit" those implementations. And in doing so my class would be
>>     >> completely broken, but I would be unaware of it.
>>     >>
>>     >> To me this is completely wrong - we should never sacrifice
>>    correctness.
>>     >> A supertype does not in general know about any subtypes and so a
>>     >> supertype's default implementation should not apply if the
>>    subtype has
>>     >> redefined that method. Any change to the "documentation" of a
>>    method is
>>     >> a change to its specification. Only the author of that change is
>>    in a
>>     >> position to say whether a default implementation in a supertype
>>    is still
>>     >> applicable - so to assume that it is by default (no pun intended)
>> is
>>     >> just wrong in my view.
>>     >>
>>     >> If redefinition of a method always re-abstracted it then, I
>>    think, no
>>     >> explicit syntax for re-abstraction would be needed.
>>     >>
>>     >> David Holmes
>>     >>
>>     >
>>     > I aggree. Only the author of the interface should say when an if
>>    the "new" default on a superinterface is adequate. I don't see any
>>    drawback when re-specification of a method in a subinterface has the
>>    semantics of re-abstraction compared to current state where the
>>    default is inherited. It certainly doesn't break any code.
>>     >
>>     > Looking from the perspective of code evolution: if an interface
>>    method was abstract (non-default) at the start than any non-abstract
>>    implementations of this interface or subinterface already specifies
>>    a concrete implementation for that method. Changing this abstract
>>    method to a default method on a superinterface does not break
>>    anything even if this method is re-abstracted on any subinterface
>>    (because class allways wins).
>>     >
>>     >   Regards, Peter
>>     >
>>     >>
>>     >
>>
>>
>>
>>
>> --
>>   -- Howard.
>>
>>


-- 
  -- Howard.


More information about the lambda-dev mailing list