Static method access dilemma and proposal: @NotInherited
Brian Goetz
brian.goetz at oracle.com
Thu Jun 27 11:58:29 PDT 2013
Stephen's proposal is workable with a language change; it is a way for
the developer to say "I intend this method to not be inherited". (One
could have an angels-on-head-of-pin argument about whether an annotation
is OK here, but that's a pretty minor part of the story so no point in
having it now.) We have no problem with considering features that make
it harder for people to make mistakes, or to give users more control,
presuming that they carry their weight.
What's mostly impractical was the additional suggestion to change the
meaning of existing Java code because we don't like the language design
choices that were made in 1997.
On 6/27/2013 2:49 PM, Paul Benedict wrote:
> 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
> <mailto: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>
> <mailto: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>
> <mailto: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