Re-specification and re-abstraction
Brian Goetz
brian.goetz at oracle.com
Thu Dec 22 14:41:37 PST 2011
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.
>
More information about the lambda-dev
mailing list