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