
Signature
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com
> > public static void main(String args[]) {
> > Class1 c = new Class1);
[quoted text clipped - 7 lines]
> maintainable code, this is a malformed program. It should not depend
> on such fine points in the JLS as how it resolves this ambiguous case.
I'm new to Java and though I have lots of experience with C and and other
languages like Smalltalk, there are are a few things in Java that are just
not obvious that I need to understand to really learn the language and the
system of selecting between redundant overloaded methods is exactly the
type of thing I don't yet understand.
Because of this thread, I found a little time yesterday to play with it and
realized as you say that the selection is based on compile time hints and
not run time reality. Because when I do something like:
Object o
o = "string";
method(o);
The method used is method(Object) and not method(String) even though the
String method would be the obvious choice if it was a run time decision.
So it's using the compile time information (o is type Object) to make the
choice instead of the actual type of the object at run time.
But I'm having a hard time grasping how this is all actually implemented
and without a good model of how it's implemented I'm feeling at a loss to
really understand what it does in all cases.
I understand that on method calls, arguments can be automatically converted
to different types, such as an int to a double, or a int to an Integer.
But is the decision about the conversion always resolved at compile time so
the conversion will always happen as it was determined to happen at compile
time? Or is this a decision that is sometimes put off to run time so it
has to produce conditional conversions?
The issue it seems to me would come up when different possible objects are
the target of the method, and that the different objects have different
sets of redundant methods to choose from.
For example we have these sorts of classes and methods:
Class Superclass
method(double)
Class Subclass extends Superclass
method(double)
method(int)
And code like this:
Superclass s;
s = (either a Superclass object or a Subclass object);
s.method(int);
So, at run time, s might be either type of object. So depending on the
type of object, either the Superclass or the Subclass methods will be
called.
But if it's a Subclass object, it can use the int method and the argument
doesn't need to be converted. But if it's the Superclass, there is no int
method, so it will want to use the double method, and convert the argument
from int to double before passing it.
So what actually happens? Does the compiler prevent such a thing from
being coded? That is, you can't add extra overloaded methods in a
subclass? Or, since the type of the s variable is Superclass, does it only
use the methods defined in the Superclass to make the decision at compile
time, and produce the code to convert the int to a double, and always call
the double method even if the receiving object is a Subclass object? i.e.,
in that case, the int method would just never be used unless the declared
type of the s variable was Subclass?
Or does it figure it all out at run time, and call the method with the int
arg when the object is a Subclass and do the conversion and call the double
method if the object is a Superclass object?
It seems the above example is exactly the type of thing that could catch
you off guard and create some unexpected bugs in your code depending on
what Java allows. That is, you try to add a new overloaded method in a
subclass to add some special handling of a specific type argument, and the
method never gets called because you were trying to apply it to an object
typed as Superclass in some sort of collection. In which case, the whole
point of polymorphism and overloading of methods would fail you, and to
make it work you would have to resort to producing code to hand check for
the object type before sending the method with something like this:
Superclass s = (something unspecified);
if (s.getClass() == Subclass.class)
((Subclass)s).method(int);
else
s.method(int);
Or you could modify Superclass and add the method(int) as a stub to call
method(double) - which would not be an option if you couldn't modify the
superclass you were trying to use.
So, without me having to actually test the above special case, can someone
give me a better idea of how java actually implements method calls so that
I can feel like I have the power to predict how Java will deal with these
sorts of special cases without having to test each special case I dream up?
Most important, how much is it forced to decide at compile time, and how
much does it leave to run time in the selection of overloaded methods and
the auto-conversion of argument types?

Signature
Curt Welch http://CurtWelch.Com/
curt@kcwc.com http://NewsReader.Com/
Stefan Ram - 10 Sep 2007 19:09 GMT
>can someone give me a better idea of how
>java actually implements method calls
See
»Method Invocation Expressions«
JLS3, 15.12
http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12
Lew - 11 Sep 2007 00:56 GMT
>> can someone give me a better idea of how
>> java actually implements method calls
[quoted text clipped - 6 lines]
>
> http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12
Same chapter that I mentioned on this subject. This chapter, Curt, really
digs into the rules. Any javac + JVM will have to implement these rules.
Different Java engines may implement them differently, but the rules are the
rules.

Signature
Lew
Ben Phillips - 11 Sep 2007 03:35 GMT
> Same chapter that I mentioned on this subject. This chapter, Curt,
> really digs into the rules. Any javac + JVM will have to implement
> these rules. Different Java engines may implement them differently, but
> the rules are the rules.
In practise, to keep code maintainable it's best to limit overloads to
differing numbers of arguments, and maybe sparingly overloads with only
varying argument types where none are related to one another (and the
primitive types and Number subclasses count as all related here), aside
from static methods where you might one for every primitive type and one
for Object, say. Static methods don't present these potential sources of
confusion since they don't get overridden.
Of course there's even trickier issues. For example:
class Parent {
public int method (String foo) { ... }
public int method (List foo) { ... }
}
class Child extends Parent {
public int method (Object foo) { ... }
}
Which is Child's method?
a) A compile error
b) An override of method(String)
c) An override of method(List)
d) An overload that overrides neither
The answer is far from obvious, since it has the same return type and an
argument type contravariant to both superclass methods'. In particular
it's far from obvious what calling super in Child.method() will do
without experimenting or reading the JLS in detail; likewise what
changes if one or both superclass methods are declared "final"...the
cleanest solution for the Java designers would clearly be to make
ambiguous possible-overrides always just overloads, or not even allow
contravariant argument types to override, so argument types have to be
identical to override, but is this what they did (and if so, which)? No
doubt the answer's in the JLS, but code whose behavior you can't predict
without consulting the legalese is unmaintainable code.
This is yet another reason why having same-number-of-arguments overloads
of non-static methods in non-final classes is simply begging for trouble.
Curt Welch - 10 Sep 2007 19:34 GMT
> > > public static void main(String args[]) {
> > > Class1 c = new Class1);
[quoted text clipped - 107 lines]
> at compile time, and how much does it leave to run time in the selection
> of overloaded methods and the auto-conversion of argument types?
Ok, I had to test the code after I posted the question to see what Java
does.
It allows you to add new overloaded methods in a subclass, so the above
type of code complies just fine. But, it seems to use the compile time
type specification of the object you are sending the method to, to make all
the compile time decisions about what type of conversion to do, and which
overloaded method to use. So in the above example, it would make the
conversion from int to double and call method(double).
So, at run time, when you have classes like this:
Class Super
method(double)
Class Sub extends Super
method(double) // a new version of this method for doubles
method(int) // overload method() to add special code for ints
And code like this:
Super array[] = new Super[2];
array[0] = new Super();
array[1] = new Sub();
for (Super s : array)
s.method(1);
The method(int) in Subclass never gets called. Only Super.method(double)
and Sub.method(double) are called.
So I think the answer to my question about how Java implements all this, is
that it uses compile time type information to determine the class, and then
uses only the methods available in that class (and it's superclasses of
course) to pick which overloaded method to use, and then hard-codes the
conversion code as needed, and hard-codes the call to the selected method
at compile time. Which means code like the above example, simply doesn't
work as you might want it to. You can't add new overloaded methods in a
subclass if you are going to try and use them through a superclass object
reference.
This however, works exactly as expected:
Subclass sub = new Subclass();
sub.method(1); // calls the method(int) in the subclass
If any of the experts here see something wrong with this, please correct
me....

Signature
Curt Welch http://CurtWelch.Com/
curt@kcwc.com http://NewsReader.Com/
Martin Gregorie - 10 Sep 2007 20:50 GMT
> For example we have these sorts of classes and methods:
>
[quoted text clipped - 14 lines]
> type of object, either the Superclass or the Subclass methods will be
> called.
s.method(int)'s argument will be widened to a double and
Superclass.method(double) is called because an int can be converted to a
double.
BUT if the subclass has a method which can't be converted, then you get
a compile-time error. The following classes (which took about 5 minutes
to write, compile and test) illustrates exactly what happens:
public class Parent
{
public void method(double d)
{
System.out.println("Parent.method(double) = " + d);
}
}
public class Child extends Parent
{
public void method(double d)
{
System.out.println("Child.method(double) = " + d);
}
public void method(int i)
{
System.out.println("Child.method(int) = " + i);
}
public void method(String s)
{
System.out.println("Child.method(String) = " + s);
}
}
public class Family
{
public static void main(String args[])
{
Parent p = new Child();
p.method(2);
p.method("string");
System.exit(0);
}
}
The code as shown will throw a compilation error because there is no
superclass method that matches method(String) even after argument
conversion:
$ javac Family.java
Family.java:8: method(double) in Parent cannot be applied to
(java.lang.String)
p.method("string");
^
1 error
BUT if you comment out line 8 the code will compile and run:
$ javac Family.java
$ java Family
Child.method(double) = 2.0
What happens is:
(1) the argument is converted at compile time to match the superclass
method
(2) the subclass method is called because it overrides the superclass
method with the matching interface.
If you add method(int) to the superclass then no type conversion occurs
and subclass.method(int) is called because it overrides the superclass
declaration.
HTH

Signature
martin@ | Martin Gregorie
gregorie. | Essex, UK
org |
Roedy Green - 10 Sep 2007 22:12 GMT
>Because of this thread, I found a little time yesterday to play with it and
>realized as you say that the selection is based on compile time hints and
>not run time reality.
There is a variant of Java called Nice that runs on the JVM that makes
the matching decision at run time.
You can fake Nice behaviour in Java with a method that expects an
Object parameter, then does a string of instanceofs to select at run
time based on the type of the object which variant method to actually
use.
see http://mindprod.com/jgloss/nice.html

Signature
Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com