Re-specification and re-abstraction

Greg Dennis gdennis at alum.mit.edu
Fri Dec 23 14:44:30 PST 2011


Sorry, I should have been a little more careful with my example. Of
course C and D should be interfaces and C should be declared to extend
D. But while I'm at it, maybe this is a slightly less contrived
example:

  interface Sorter {
    /**
     * Sorts the elements in the given list.
     */
    void sort(List lst);
  }

  interface StableSorter extends Sorter {
    /**
     * Sorts the elements in the given list, maintaining the
     * relative order of equal elements.
     */
    void sort(List lst);
  }

If a default implementation of Sorter were later provided that does
not do a stable sort, it would break the StableSorter contract.

Greg


On Thu, Dec 22, 2011 at 8:56 PM, Greg Dennis <gdennis at alum.mit.edu> 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 no-op-ness of "exact redeclaration of interface method" is respected
>>> either way if the definition of "exact" is adequate.
>>
>> Yes, if you exactly redeclare the default too, it is also a no-op.  So,
>> more precise statement: "exact redeclaration of the return type, name,
>> and signature, but no default clause."
>
> Long-time lurker here chiming in. It seems to me a problem with this
> calling this an "exact redeclaration" is that all of these things may
> stay the same (return type, name, signature), and yet the *contract*
> of the method may still have changed. That new contract may be given
> in the Javadoc accompanying the method, but does not require any
> change in method signature.
>
> For example, consider class C:
>
>  class C {
>    /**
>     * Precondition: a is not null
>     */
>    R method m(A a);
>  }
>
> When a precondition is false, the method can do anything --- return a
> value, throw an exception, go into an infinite loop, anything. Now
> class D may extend it and drop the precondition:
>
>  class D {
>    /**
>     * If a is null, returns null.
>     */
>    R method(A a);
>  }
>
> Since the precondition is dropped, D is still a true subtype of C. But
> if the author of C were to later provide a default implementation to m
> that throws an exception when given a null argument, it would break
> the contract of D. That seems very undesirable.
>
> The argument is that the current semantics preserves the "no-op"
> behavior of a redeclaration. Another way to look at it is that a
> redeclaration has always meant "reabstract" and that the "no-op"
> treatment has merely been an optimization since concrete
> implementations in interfaces were never before possible :)
>
> I'll now scurry back into lurker mode ...
>
> Greg


More information about the lambda-dev mailing list