Search

Categories

Links

Referers

@Override

May 10 2006, 08:57:26 PM PDT »Java»Language Comments [20]
I'm currently looking at how javac handles @Override. Consider the current specification of @Override:
Indicates that a method declaration is intended to override a method declaration in a superclass. If a method is annotated with this annotation type but does not override a superclass method, compilers are required to generate an error message.

There are a few subtle points that may escape the casual reader:

  • it says superclass not supertype
  • override and implements are not mutually exclusive

There are a few surprising consequences of this:

    abstract class C1 {
        public abstract void m();
    }
 
    class C2 extends C1 {
        @Override
        public void m() {}
    }

Although the method C2.m implements the method C1.m, it also overrides it. So this is OK according to the current specification and javac accepts it. The next example is even more convoluted:

    public interface Test {
        void m();
    }

    abstract class A implements Test {
        // m() is inherited from Test
    }

    class B extends A {
        @Override
        public void m() {}
    }

This is also legal since m is a member of the abstract class A, B.m is overriding (and implementing) a method in a superclass. However, javac fails to accept this program.

So thought about it and came up with this specification:

Indicates that a method declaration is intended to override a method declaration in a supertype. If a method is annotated with this annotation type but does not override a supertype method, compilers are required to generate an error message

However, this doesn't work as you would expect: although override and implements are not mutually exclusive, override is not a "superset" of implements:

    interface A {
        void m();
    }

    class B implements A {
        public void m() {} // implements but doesn't override
    }

Whereas:

    interface A {
        void m();
    }

    interface B extends A {
        void m(); // overrides but doesn't implement
    }

Confused? Then you're getting there ;-)
So we tried this one:

Indicates that a method declaration is intended to override a method declaration in a supertype. If a method is annotated with this annotation type but does not override or implement a supertype method, compilers are required to generate an error message

However, what about (currently accepted by javac):

    interface Foo {
        @Override
        String toString();
    }

So does Foo.toString override or implement a method in a supertype? Not really, the JLS is a bit convoluted here but basically says that although Object is a direct supertype of Foo, Foo does not inherit Object.toString because Foo itself declares a toString method...

Now what? We thought about it and came up with:

Indicates that a method declaration is intended to override a method declaration in a supertype. If a method is annotated with this annotation type but is not in fact override-equivalent to any method declared in a supertype, compilers are required to generate an error message.

So how is this different? Rather than relying on the definition of override or implements in the JLS we simply say what we intended to say all along: if a similar method exists in a supertype, then you may use @Override.

So then Eugene says: what about visibility. Oh boy:

Indicates that a method declaration is intended to override a method declaration in a supertype. If a method is annotated with this annotation type compilers are required to generate an error message unless either the method is override-equivalent to a [update: public or protected] method in Object, or the method does override or implement a method declared in a supertype.

I hope to have this ready for b86.

Post a Comment:
Comments are closed for this entry.
Comments:

If you bypass "overrides or implements", make sure that only visible methods from supertypes are accounted.

Posted by Eugene Vigdorchik on May 10, 2006 at 11:24 PM PDT #

What I've always wanted @Override to mean was (informally) "changes the implementation". I'm often annoyed that I can use @Override if the overridden superclass method is abstract. The submitter of bug 6399361 that you've linked to seems to agree with me.

Obviously, your proposed changes go in the other direction, allowing @Override in more places instead of less. Maybe the annotation needs an optional element to allow the programmer to be more specific.

Posted by Bas de Bakker on May 11, 2006 at 12:07 AM PDT #

Eugene, no bypassing. The necessary compiler changes are trivial: before javac would only look at superclasses and now it also considers interfaces. This is without changing the method that is used to implement javax.lang.model.util.Elements.overrides.

Posted by Peter von der Ahe on May 11, 2006 at 12:50 AM PDT #

Peter, Peter, actually I thought about JLS changes. Seems like the following will be more correct: "Indicates that a method declaration is intended to override a method declaration in a supertype. If a method is annotated with this annotation type but is not in fact override-equivalent to any visible method declared in a supertype, compilers are required to generate an error message."

Posted by Eugene Vigdorchik on May 11, 2006 at 12:58 AM PDT #

Oh boy. Good point. Yet another revision ;-)

Posted by Peter von der Ahe on May 11, 2006 at 01:20 AM PDT #

Bas, I guess you can't satisfy everybody. My observation has been that most people are looking for something that says (informally): "changes the specification". But perhaps me and my colleagues are slightly biased when it comes to the importance of specification. However, since our public bug pages only update every 24 hours, you didn't see the reference to 5008260.

Posted by Peter von der Ahe on May 11, 2006 at 01:33 AM PDT #

For what it's worth, the specification you now have, based on the examples you give, is 100% inline with how I'd always *assumed* it was *meant* to work :) Meaning with each example I agreed immediately whether it should be allowed or not.

Posted by Andrew Thompson on May 11, 2006 at 06:01 AM PDT #

Hi, You guys sure know how to party! B^> I was just thinking 30s before opening your page about how much I wish that we could retrofit this into the C++ compilters that I have to use. Informally I expect @Override to mean "this function replaces existing behaviour or implements something mandated by an interface or abstract class"... So if I am not replacing/implementing then I expect an error. Rgds Damon Rgds Damon

Posted by Damon Hart-Davis on May 11, 2006 at 06:23 AM PDT #

Hello. I have a comment. The method in the current type is always overriding, because it is the one that will be invoked polymorphically. Overriding is a purely syntactic mechanism -- it is a consequence of declaring a method with an override-equivalent signature -- therefore, the annotation should match against any such syntax. Also, the annotation declaration is scoped -- and so attempting to take the annotation out of a purely syntactic framework can't work. I'd say that Eugene Vigdorchik's description works for a compiler contract: though you have done some of the compiler implementor's work for them! Good luck; and feel free to let me know any comments. - Steev Coco.

Posted by Steven Coco on May 11, 2006 at 09:40 AM PDT #

I vote for the spec change, it's cool if @Override works between interfaces :
interface A<T> [
  Collection<? extends T> m(T t);
}
interface B extends A<CharSequence> {
  @Override
  List<String> m(CharSequence seq);
}
because with return type covariance and generics, it could be not obvious.
Rémi Forax

Posted by Rémi Forax on May 12, 2006 at 02:41 AM PDT #

Hi.

I think some of the spec might have been missed or something. See if you agree with these:

For the subinterface example: Section 9.4.2 unambigously says that a subinterface declaring an override-equivalent method overrides that method.

For the class implements interface example -- being that it implements but does not override -- I think this is a misunderstanding of the spirit of the spec. Section 8.4.8 says: "Moreover, if m1 is not abstract, then m1 is said to implement any and all declarations that it overrides." Taken even on its own, but also with the start of that section, saying "a class inherits all methods from superclasses and superinterfaces", this seems to simply state that this is both overridden and implemented. When the distinction is being made: "this method overrides, that method implements", it is for clarity in behavior; but not syntax.

I really don't think the strictest usage of the word is appropriate. I do not believe the specification had that intent in several places. Interfaces are really described simply as - always being abstract, and - containing all abstract methods. They are not so very far from a class.

I personally feel that it is completely valid scientifically-speaking to think of two definitions for overriding:

  1. Overriding, behaviorally
  2. Overriding, syntactically

Again, not to suggest using rogue terms, but I feel this is accurate:

Looking at the subinterface example: Within the curly braces that contain this annotation declaration, this is the method that's going to be implemented. In other words, the class that implements B is unambiguously implementing B's method -- B has merely inherited any other methods from A, but the class extending B is contractually bound only to B. And, since the interface can refine the method signature, it falls under the same syntactic mechanism.

I think these aspects are a byproduct of the rigid viewpoint you get from single inheritance: the syntactic construct is extremely accurate when translated into the object implementation. "Java kicks butt."


Other comments and observations:

- Section 8.4.3 so happens to say: An instance method that is not abstract can be overridden by an abstract method. And it's the case that all interfaces implement an abstract method with the same signature as visible methods in Object. So to me this all means the an interface "overrides" toString if it is declared there.

- Notice that it is possible to modify the imnplementation of Object, and still the above interface requires any implementation to provide a body somewhere for that method. So again from the syntactic viewpoint, if I am declaring this signature, I really do mean it -- I am overriding any other occurrance that so happens to exist.

- No matter which of these options is chosen, in the end it is possible to compile legally and then have the dependent implementation change in such a way that the depending classes will no longer compile.

- The annotation is a modifier, and it can only be constructed with compile-time constants, so again I say it is very much in the syntactic realm.

Hopefully this is somewhat helpful. Are there any comments on any of this?

Thanks again, and best regards,
Steven.

Posted by Steven Coco on May 12, 2006 at 08:09 AM PDT #

Hi. Oops: It is 9.4.1 http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html#9.4.1 Has that got it?

Posted by Steven Coco on May 12, 2006 at 09:45 AM PDT #

For the subinterface example: Section 9.4.2 unambigously says that a subinterface declaring an override-equivalent method overrides that method.

I do not see that in the JLS:

http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html#9.4.2

Section 9.4.2 says when an interface method is overloaded.

Posted by Peter von der Ahe on May 12, 2006 at 09:46 AM PDT #

[Forum posting woes...]

Sorry: section 9.4.1 on the above:

http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html#9.4.1

Yes?

Regards,
Steven.

Posted by Steven Coco on May 12, 2006 at 09:49 AM PDT #

Steven,

I'm not sure I get your point ;-)

You should also see issue 6424261.

Posted by Peter von der Ahe on May 12, 2006 at 10:10 AM PDT #

Apology:

Hello Peter, and anyone else reading. I have to post an apology for my lengthy comment above. I did actually somehow mis-read Peter's blog entry: I was commenting there on things that I now see do not in fact appear in the entry. Everything Peter wrote just makes fine sense; and my comment is not really pertinent actually.

My Sincere aplogies to Peter.

- Steev Coco.

Posted by Steven Coco on May 12, 2006 at 01:53 PM PDT #

P.S.:

For sure: my very off-base musings are all my own concoction also. Sorry about all that. That is all.

Steven.

Posted by Steven Coco on May 12, 2006 at 01:58 PM PDT #

Thank you very much for your work. We can't annotate a static method inherited from a super class with the Overrideannotation (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6359949). But, I want to annotate it with any annotation. I don't think that we have to distinguish "hide" from "override" and/or "implement". The best solution is to deprecate the Override annotation and introduce an annotation (e.g. java.lang.Redefined annotation) that represents "override", "implement", and/or "hide". The realistic solution is to extend the meaning of the Override annotation.

Posted by Manabu Nakamura on July 23, 2006 at 09:22 PM PDT #

Static methods are not inherited and we have no intention to support that. If you feel that you need to hide a static method, something is probably wrong with your design. You should avoid hiding static methods as it will lead to confusion: many novice Java developers have a problem figuring out the difference between overloading and hiding, so you should avoid it.

Posted by Peter von der Ahe on July 23, 2006 at 09:56 PM PDT #

Here's a trick for getting @Override-like behavior for methods declared in interfaces:
  interface Foo {
    /** do something */ void do();
  }
  class Bar implements Foo {
    /** {@inheritDoc} */ public void do();
  }
If you check for well-formed Javadoc, your @inheritDoc will complain if Bar.do() doesn't implement/override Foo.do().

Posted by Mick Killianey on April 24, 2007 at 09:42 AM PDT #

Java is a trademark of Sun Microsystems, Inc.
Copyright © 2006,2007 Peter von der Ahé