Static method access dilemma and proposal: @NotInherited
Paul Benedict
pbenedict at apache.org
Thu Jun 27 10:50:24 PDT 2013
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), 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