Static method access dilemma and proposal: @NotInherited

Paul Benedict pbenedict at apache.org
Thu Jun 27 11:49:06 PDT 2013


If neither an annotation nor grammar change is appropriate, I am puzzled by
what remaining option could exist.


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

> I got what you were saying.  What I was telling you is that our
> compatibility goals are higher than that, and that at the very least it
> would take probably 2-3 major versions, even if we were willing to do this.
>  We have a very limited budget for this kind of incompatibility; we want to
> spend it where it will provide the most payoff.  Here, our excuse is pretty
> lame: "we think Java should have been designed the other way, so we're
> changing it."  That's just a silly thing to spend our incompatibility
> budget on.  (And I agree with you that this language feature was a mistake.)
>
>
>
>
> On 6/27/2013 2:32 PM, Paul Benedict wrote:
>
>> 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
>> <mailto: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 <mailto: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>
>>             <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