|
|
|
[
Permlink
| « Hide
]
Arno Unkrig - 22/Apr/07 02:54 PM
I will try to look into this one in the next days...
I get
$ java -cp janino.jar org.codehaus.janino.Compiler JaninoTest.java File JaninoTest.java, Line 17, Column 13: Invocation of constructor/method with actual parameter type(s) "java.lang.String, java.lang.String, java.lang.String" is ambiguous: "void JaninoTest.doIt(java.lang.String, java.lang.Object, java.lang.Object)" vs. "void Base.doIt(java.lang.String, java.lang.String, java.lang.String)" org.codehaus.janino.CompileException: 1 errors while compiling unit "JaninoTest.java" $ Problem reproduced. The example can be even be simplified to reproduce the same error:
class Base {
public static void doIt(String msg, String left, String right) {
System.err.println("Base.a:doIt(" + msg + ", " + left + ", " + right + ")");
}
// public static void doIt(String msg, Object left, Object right) {
// System.err.println("Base.b:doIt(" + msg + ", " + left + ", " + right + ")");
// }
}
public class JaninoTest extends Base {
public static void doIt(String msg, Object left, Object right) {
System.err.println("JaninoTest:doIt(" + msg + ", " + left + ", " + right + ")");
// Base.doIt(msg, left, right);
}
public static void main(String[] args) {
doIt("a", "b", "c");
}
}
Hm... to me it seems like javac is wrong here.
JLS 2 says: JLS2: 15.12.2.2 Choose the Most Specific Method Let m be a name and suppose that there are two declarations of methods named m, each having n parameters. Suppose that one declaration appears within a class or interface T and that the types of the parameters are T1, . . . , Tn; suppose moreover that the other declaration appears within a class or interface U and that the types of the parameters are U1, . . . , Un. Then the method m declared in T is more specific than the method m declared in U if and only if both of the following are true:
A method is said to be maximally specific for a method invocation if it is applicable and accessible and there is no other applicable and accessible method that is more specific. If there is exactly one maximally specific method, then it is in fact the most specific method; it is necessarily more specific than any other method that is applicable and accessible. It is then subjected to some further compile-time checks as described in §15.12.3. It is possible that no method is the most specific, because there are two or more maximally specific methods. In this case:
In your example we have
So neither of the two methods is more specific than the other. Considering the rest of the JLS2 section, JANINO is right to issue a compile-time error. Amazingly, all of JAVAC 1.6.0, 1.5.0 and 1.4.1 compile the example without errors and warnings (and call "Base.doIt(String, String String)"). Only JAVAC 1.2.2 says $ jdk-1.2.2/bin/javac JaninoTest.java JaninoTest.java:17: Reference to doIt is ambiguous. It is defined in void doIt(java.lang.String, java.lang.Object, java.lang.Object) and void doIt(jav a.lang.String, java.lang.String, java.lang.String). doIt("a", "b", "c"); ^ 1 error $ – it seems to share the opinion of JANINO and JLS2! JLS3 is quite difficult to understand: JLS3: 15.12.2.5 Choosing the Most Specific Method If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen. The informal intuition is that one method is more specific than another if any invocation handled by the first method could be passed on to the other one without a compile-time type error.
In addition, one variable arity member method named m is more specific than another variable arity member method of the same name if either:
The above conditions are the only circumstances under which one method may be more specific than another. A method m1 is strictly more specific than another method m2 if and only if m1 is more specific than m2 and m2 is not more specific than m1. A method is said to be maximally specific for a method invocation if it is accessible and applicable and there is no other method that is applicable and accessible that is strictly more specific. If there is exactly one maximally specific method, then that method is in fact the most specific method; it is necessarily more specific than any other accessible method that is applicable. It is then subjected to some further compile-time checks as described in §15.12.3. It is possible that no method is the most specific, because there are two or more methods that are maximally specific. In this case:
This sounds to me like the type where the two methods are defined (JaninoTest and Base) no longer matter, and thus the invocation is not ambiguous. But I'm not sure. Notice that JLS3 maps to JDK 1.5, so JDK 1.4.1 should implement the behavior defined by JLS2!? Adam, what is your understanding of the theory and practice?
Well, it doesn't say where method T and method U come from, in the inheritance chain. Only that they are defined in a class or a method. So, for instance, T is not more specific than U, but if you swap T and U, then it is.
All parameters of U can be converted to parameters of T, which, by definition, means it's more specific. Well, since this JLS2 incompatibility is about one compile error LESS, I changed JANINO to mimic the behavior of JAVAC 1.4.1, 1.5.0 and 1.6.0.
Will be released as 2.5.8. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||