Static method access dilemma and proposal: @NotInherited

Paul Benedict pbenedict at apache.org
Thu Jun 27 11:32:05 PDT 2013


Brian, if you're focus is 99/100% compatibility, I guess it won't work.
However, if you loosen the requirements, it should be possible to overcome
the compatibility reasons with this plan:

For class files <= 52.0, the JVM will resolve static method inheritance.
Otherwise, when code is recompiled for JDK 9+ (>= 53.0), static method
inheritence will be rejected. This should be made even easier with the
deprecation of --source/--target (JEP 182). If absolute source
compatibility is necessary, the source compatibility could be controlled by
another JVM option.


On Thu, Jun 27, 2013 at 1:14 PM, Brian Goetz <brian.goetz at oracle.com> wrote:

> Total agreement that it was a mistake to have them be inheritable. Static
> methods in interfaces don't have this defect.  (And we took a hit for that
> inconsistency.)  Unfortunately what you suggest for 9 is impractical for
> compatibility reasons.
>
> Overall I like Stephen's proposal here (except I am not convinced that it
> is suitable for an annotation, but that's a pretty superficial aspect of
> it.)  Anything that moves us towards being able to fix this problem over
> time is good.
>
>
> On 6/27/2013 1:50 PM, Paul Benedict wrote:
>
>> Stephen, it's an interesting idea. Bikeshed moment.... At the cost of
>> having to recompile future code, I'd rather wish to have static methods on
>> classes not be inheritable in JDK 9 and onward. Then the same behavior can
>> be predictable across classes or interfaces. Fixing a bad language design
>> is probably better than patching things up with @NotInherited.
>>
>>
>> On Thu, Jun 27, 2013 at 12:20 PM, Stephen Colebourne
>> <scolebourne at joda.org>wrote:
>>
>>  The addition of static methods on interfaces has given developers a
>>> new very useful tool. However, it has also produced a dliemma.
>>>
>>> A static method on a class is accessible/"inherited" by subclasses.
>>> Thus SubClass.foo() is just as good as SuperClass.foo() for accessing
>>> the static method defined on SuperClass. By contrast, with static
>>> methods on interfaces, this is not possible - a static method on an
>>> interface is not "inherited" (a Good Thing).
>>>
>>> The dliemma, from JSR-310
>>> (https://github.com/ThreeTen/**threeten/issues/321<https://github.com/ThreeTen/threeten/issues/321>),
>>> is that I _really_
>>> want to avoid the inheritance of static methods from one abstract
>>> class (Chronology), as the methods make no sense at all to be called
>>> on the subclasses, and in fact they may cause bugs. Thus, the new
>>> language feature pushes me to change the abstract class to be an
>>> interface *just to get the new static method behaviour*. In essence I
>>> have to make a new trade off between the right tool for the job
>>> (abstract class) and the right tool to avoid static method bugs
>>> (interface).
>>>
>>> It occured to me that as this was a new dliemma, I should report it
>>> here on lambda-dev. And propose a possible solution.
>>>
>>> Consider a new annotation @NotInherited that is only applicable to
>>> static methods. If a developer places it on a static method, then the
>>> method cannot be invoked by subclasses:
>>>
>>> public class A {
>>>    @NotInherited
>>>    public static void foo() {..}
>>> }
>>> public class B extends A {
>>> }
>>> {  // other code
>>>    A.foo();  // compiles
>>>    B.foo();  // would not compile with this proposal
>>> }
>>>
>>> - Many IDEs support something similar today, but this would be
>>> enforced at the compiler level.
>>> - It is similar to @Override in conceptual scope, and is therefore
>>> suitable for an annotation.
>>> - It would not change the compiled bytecode at all, other than the
>>> standard storage for the additional annotation.
>>> - There are no reflection, security or backwards compatibility issues
>>> that I can see.
>>> - Adding the annotation to a previously published API would be
>>> backwards incompatible at the source level, but not the binary level
>>> - When compiling B against a previously compiled A, the annotation
>>> would be read from A's bytecode.
>>> - The annotation would not be processed by the JVM or verifier, thus
>>> B.foo() would be valid if it could be compiled (such as in a separate
>>> compilation scenario).
>>> - The change appears to be small, and thus not require a large effort
>>> to implement
>>>
>>> The annotation could be added to the JDK without enforcing it in
>>> javac, but that would seem to be a change not worth doing as it would
>>> rely on IDEs.
>>>
>>> Its easy to say that this is an old problem and so nothing needs to be
>>> done. But I hope I've tried to indicate that I think lambda's static
>>> methods on interfaces has changed the nature of the old problem and
>>> made it potentially more problematic in code design terms.
>>>
>>> Thoughts?
>>> Stephen
>>>
>>>
>>>
>>


More information about the lambda-dev mailing list