Static method access dilemma and proposal: @NotInherited
Stephen Colebourne
scolebourne at joda.org
Thu Jun 27 10:20:02 PDT 2013
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