Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two methods with same erasure aren't necessary override-equivalent (or they signatures aren't subsignatures between them)?

Im reading the incredible book “a programmer's guide to java scjp certification” for jdk6 and theres a section about generic overriding. On it is described subsignature and override-equivalent and describes some examples of override-equivalent that I quote:

Given the following three generic method declarations in a class:

static <T> void merge (MyStack<T> s1, MyStack<T> s2) { /*...*/ }

static <T> void merge (MyStack<T> s1, MyStack<? extends T> s2) { /*...*/ }

static <T> void merge (MyStack<T> s1, MyStack<? super T> s2) { /*...*/ }

After erasure, the signature of all three methods is: merge(MyStack, MyStack) i.e., the signatures of the methods are override-equivalent, hence these methods are not overloaded.

Im not totally agree that these methods are override-equivalent , in fact i think the methods have a “name clash by erasure” but none is subsignature of the other one… possibly im wrong so i want some light on this.

The definitions of subsignature makes me think that they arent subsignatures between them.

In JSL 6 #8.4.2 Method Signature (http://docs.oracle.com/javase/specs/jls/se6/html/classes.html#8.4.2)

Two methods have the same signature if they have the same name and argument types. Two method or constructor declarations M and N have the same argument types if all of the following conditions hold:

  • They. have the same number of formal parameters (possibly zero)

  • They have the same number of type parameters (possibly zero)

  • Let <A1,...,An> be the formal type parameters of M and let <B1,...,Bn> be the formal type parameters of N. After renaming each occurrence of a Bi in N's type to Ai the bounds of corresponding type variables and the argument types of M and N are the same.

The signature of a method m1 is a subsignature of the signature of a method m2 if either m2 has the same signature as m1, or the signature of m1 is the same as the erasure of the signature of m2

...

Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.

In JSL 8 # 8.4.2. Method Signature (http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.4.2)

Two methods or constructors, M and N, have the same signature if they have the same name, the same type parameters (if any) (§8.4.4), and, after adapting the formal parameter types of N to the the type parameters of M, the same formal parameter types.

The signature of a method m1 is a subsignature of the signature of a method m2 if either:

  • m2 has the same signature as m1, or

  • the signature of m1 is the same as the erasure of the signature of m2.

Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.

EDIT 1

To put it simple, my doubt is that from the subsignature definition in respect to erasure i understand that "one signature without erasure is equal to the erasure from the other signature".. and not that "both signatures after erasure are equal" .. its subtle but important (by the way, the override-equivalent definition is based on subsignature definition, thats why i ask in terms of subsignatures)

like image 272
user1546652 Avatar asked Jul 04 '15 21:07

user1546652


1 Answers

TL;DR

The wording of the book does not hang together very well here, in my opinion. Overloading is defined in terms of a negation of override-equivalence, as per the JLS (8.4.9) (paraphrasing: if two methods with the same name exist but are not override-equivalent, then they will overload).

But the example given is one where the methods are NOT override-equivalent, but DO cause a compile time error for other reasons (Name clash - a specific compile time error specified in JLS 8.4.8.3) and therefore do not overload.


Preamble

As I understand it, you're raising a question about the exact semantics of this sentence clause:

"...or the signature of m1 is the same as the erasure of the signature of m2"

In combination with

m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.


Your book implies that this should be interpreted as

"or the erasure of the signature of m1 is the same as the erasure of the signature of m2"

(added words in bold italic).

Whereas you would interpret it as

"or the signature of m1 (without erasure) is the same as the erasure of the signature of m2"

Your interpretation is correct. I don't think the sentence is ambiguous, therefore I think that interpreting it in the first way (i.e. that the erasure of both signatures is the same) is incorrect. You might like to look at this related answer to add weight to my opinion here (I found it as I wanted to check my understanding too).


Answer (however...)

The section of the book you're quoting is actually trying to describe overloading.

Now - when thinking about overloading - the JLS (8.4.9) says that:

If two methods of a class (whether both declared in the same class, or both inherited by a class, or one declared and one inherited) have the same name but signatures that are not override-equivalent, then the method name is said to be overloaded.

This has been consistent since at least Java 6. This is where the link between override-equivalent and overloading stems from.

OK - so your methods would overload because they are not strictly override-equivalent. Right?

Wrong.

Because just above that section in 8.4.8.3, the JLS puts in a specific compile time error:

It is a compile-time error if a type declaration T has a member method m1 and there exists a method m2 declared in T or a supertype of T such that all of the following are true:

  • m1 and m2 have the same name.

  • m2 is accessible from T.

  • The signature of m1 is not a subsignature (§8.4.2) of the signature of m2.

  • The signature of m1 or some method m1 overrides (directly or indirectly) has the same erasure as the signature of m2 or some method m2 overrides (directly or indirectly).

This is the scenario in your example. Just below that section, it clarifies why it is necessary:

These restrictions are necessary because generics are implemented via erasure. The rule above implies that methods declared in the same class with the same name must have different erasures. It also implies that a type declaration cannot implement or extend two distinct invocations of the same generic interface.

Side note

The example in the book is a strange one, because Java would not allow overriding of static methods (rather the signature of a method in a subclass could hide that in the superclass). This makes the concept of not being override-equivalent a bit tricky for a learner in my view. However, you can remove the static and still see the effect they are trying to demonstrate.

like image 68
J Richard Snape Avatar answered Nov 14 '22 22:11

J Richard Snape