Static method access dilemma and proposal: @NotInherited

Jonathan Gibbons jonathan.gibbons at oracle.com
Thu Jun 27 11:53:54 PDT 2013


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