Static method access dilemma and proposal: @NotInherited

Stephen Colebourne scolebourne at joda.org
Thu Jun 27 15:45:49 PDT 2013


This sounds like a good start. Really, IDEs should stop offering
B.foo() as their default setup. The annotation/keyword is just the
extra step to enforce that at the users behest.
Stephen

On 27 June 2013 19:53, Jonathan Gibbons <jonathan.gibbons at oracle.com> wrote:
> It would be reasonable to add a lint warning in the [static] category
> in situations where a static method is invoked through a subclass.
> We already warn in cases where a static method is invoked through
> an instance of a class.
>
> -- Jon
>
> On 06/27/2013 11:36 AM, Brian Goetz 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>), 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