• Post Reply Bookmark Topic Watch Topic
  • New Topic

Why call int version,not char version?  RSS feed

 
Greenhorn
Posts: 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

On line 4,I think char version is the best match for compiler.
But why call int version,not char version?

ps:
Added the [ code ] and [ / code ] tags, without the spaces that is....
- satya
[ January 09, 2002: Message edited by: Madhav Lakkapragada ]
 
Bartender
Posts: 2205
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Wow. this is really a head scratcher.
There's some interaction going on between the overriden methods, and the reference used to access them. If you change

TO

then your method call works as expected.
I couldn't find anything in JLS to explain this.
Until I hear different I'm going with "compiler bug."
Rob
[ January 09, 2002: Message edited by: Rob Ross ]
 
Greenhorn
Posts: 29
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
man,
this is really a tough one
ranchers.... anyhelp !!
 
andrew
Greenhorn
Posts: 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

If i change line 4 to "Child p = new Child();", and change the method "doit" definition, then compile it ,Oh My god! It reports compile time error!!!
 
Ranch Hand
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
"andrew"
your name doesn't agree with the javaranch guidelines. Please take a moment and re-register after reviewing the guidelines at http://www.javaranch.com/name.jsp
thanks for your cooperation.
- satya
 
Madhav Lakkapragada
Ranch Hand
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you guys are up all night, please refer to these two links of JLS which explain such scenarios. I gotto go for now....
1. JLS 15.12.2 Compile time Determenation of Method Signature.
2. JLS 5.3 Method Invocation Conversions.
I will check on this thread tomorrow morning.
regds.
- satya
[ January 09, 2002: Message edited by: Madhav Lakkapragada ]
 
Rob Ross
Bartender
Posts: 2205
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Well the compiler knows how to do the right thing as long as the methods are not being overriden, so I know the compiler could resolve the overloaded versions if it really wanted to !

Produces this output:
Char Version
Int Version
Rob
 
High Plains Drifter
Sheriff
Posts: 7292
Netbeans IDE VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
< mild_rant > Let's describe this problem. Letting source code stand as implied conversation is starting to wear on me. < /mild_rant >
The overridden method here narrows the parameter type from int to char. The run-time system is now "supposed to know" that when a char is coming Child's doIt() should be called. But you've promised the compiler that p.doIt() will conform to Parent's interface. Hence when a char is received, it's widened to an int. The child override is no longer a valid method to call, and the compiler cannot implicitly narrow, but y'all already knew that.
 
Rob Ross
Bartender
Posts: 2205
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Interesting. I'm going to have to digest this one.
This seems to imply that there is a restriction with regards to method overloading of inherited methods that I have never had to think about before. In fact, this kind of problem has never come up in my day to day code, so it must not be that big of a restriction in actual practice.
It's fascinating that the more you learn, the more you realize you didn't know!
 
Ranch Hand
Posts: 411
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi, guys
One interesting moment :
If you're setting char parameter in both methods, Child.doIt() will be called. Interesting....

================================================
class Child extends Parent
{
public static void main(String [] args) {
Parent p = new Child();
System.out.println(p.doIt('R')); //Line 4
}
char doIt(char c) {
System.out.println("Char Version");
c='V';
return (char)c;
}
}
class Parent {
char doIt(char i) {
System.out.println("Int Version");
i='S';
return (char)i;
}
}
================================================
Regards,
Jamal
 
Rob Ross
Bartender
Posts: 2205
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This is just an example of overriding a method, not overloading, so this is the expected behavior.
 
Ranch Hand
Posts: 87
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The discussion here is simply great and very knowledgeable.

--Nisheeth
 
Madhav Lakkapragada
Ranch Hand
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks, Michael.
- satya
 
Greenhorn
Posts: 12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Thanks all!
I am glad to receive so many replies.
The more we discuss, the more we get!
 
Ranch Hand
Posts: 44
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
is it method overloading or overriding? i think it's method overloading, one inherited from superclass with int parameter, the other in its own class with char parameter.
actually i'm still confused. i was unable to find the answer in jls. can anybody pls help me explain it again?
 
Madhav Lakkapragada
Ranch Hand
Posts: 5040
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Andrew:
Thanks for registering with a valid name.
Just so you know, your old account "andrew" will be closed.
Thanks.
- satya
 
Michael Ernest
High Plains Drifter
Sheriff
Posts: 7292
Netbeans IDE VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Here's how I phrase the question I believe we have come to: What happens when you extend a class and override a method, but narrow its parameter type? This discussion has begun with a specific case using int and char. One good way to continue. What if Parent has doIt(int), Child has doIt(char) and Child2 has doIt(byte)? What behavior would you want when Child and Child2 instances both have Parent references?
This gets a little more interesting when we trade in primitives for objects. And while I know it's helpful to SCJP candidates to pose coded head-scratchers and go from there, I'll offer general ideas where they seem appropriate.
 
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi all
The links that Madhav provided are the needed for answering this question. However I admit they are not easily understable the first time you read it.
Nor the third I would say
The method in superclass is not overriden by the method in subytpe because their signature are not identical. They differ in the argument type.
It is overloaded, though in diferent classes overloading is still possible.
Let's see this invocation:
"System.out.println(p.doIt('R'));"
Always start the search for a method declaration in the type of the reference used in the call. That is Parent. There is a method in Parent
"char doIt(int i)"
Now is time to question is it a (non private, non final) instace method? Yes it is. Thus it could have been overriden. For determining whether a derived method should be called search the type of the instance holded by p. That is search Child for an overriding method. There is no one, so the Parent method is called.
Now I will apply the same process to the code posted by Andrew:
" Child p = new Child();
System.out.println(p.doIt('R'));"
Searching Child for methods named doIt result in
char doIt(int i) //declared in Child
char doIt(char i) //inherited from Parent
both are aplicable because 'R' can be converted to int without explicit cast. Which one will be chosen? JLS 15.12.2.2 will explain that:
We need to find the most specific method of both and that will be the winner.
char is widenning convertible to int, not the other way. Thus the method inherited from parent has one point. However we need to consider now the classes that declared both doIt methods. Child is widenning convertible to parent, not the other way. So the method declared in Child has another point.
There is a draw here. None of the methods are more specific than the other and the compiler will complain.
Search the Ranch for more examples about ambigous calls.
 
"The Hood"
Sheriff
Posts: 8521
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Very nice explaination Jose!
 
Ranch Hand
Posts: 1873
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hey all,
very interesting discussion and good explanation by Jose.
i tried to fit some example to this and understand.
e.g. say there are two persons.
1. parent,
2. child (chid of parent)
child runs health center and internally cooperates with his/her parent, who is again in turn can run health services.
there r following specifications,
1. child can handle 'fat' persons
2. parent can ONLY handle 'thin' persons.
3. child runs the center and so everybody initially comes to child only.
4. every person that comes to child is actually referred by some other doctor to go to either child or parent, explicitly.
5. the person's doctor could also just say, "meet child and he will guide u appropriately"
6. if parent doesn't have capability to handle the person (which child knows depending upon the person is being fat or thin), then child serves the person (assuming every person can be classified as thin or fat only).
7. child doesn't handle thin persons with age > 60 as he doesn't have enough tools for their special treatments
8. treatment for a thin person with age <=60 can be done equally well with equipments for a fat person's treatment
so, when somebody comes to child for health request he delegates the request or serves himself.
and i have the following java code to illustrate analogy with this example,

now, consider following scenarios,
1. a thin person comes to child saying the doctor referred to go to parent,
Response from child:
child sends the person to the parent.
Analogy with java code:
Parent p = new Child();
p.doIt('R');
2. a fat person comes to child saying "the doctor referred to come to you"
Response from child:
okay. i will treat u.
Analogy with java code:
Child c = new Child();
c.doIt('R');
3. a fat person comes to child saying "the doctor just mentioned your name and said u 'll guide me where to go"
Response from child:
okay. i handle all 'fat' persons and so i will treat u.
Analogy with java code:
Child c = new Child();
c.doIt(12.34);
4. a thin person comes to child saying "my doctor told me that u will guide me and my age is 62" (specification 7 applies)
Response of child:
okay. i'll get u in touch with my parent.
Analogy with java code:
Child c = new Child();
c.doIt("hello");
5. a fat person comes to child saying "the doctor told me to go to ur parent"
Response from child:
well, my parent doesn't handle fat ppl. so i will have to treat you.
Analogy with java code:
Parent p = new Child();
p.doIt(1234L);
NOTE: THis would not compile as there is no method accepting long argument in parent. so, actually it can't be mapped to real example i have but imagine if that is possible then i would have invoked child's doIt(long)
6. a thin person with age = 30 comes to the child saying "my doctor told me to go to ur parent"
Response from the child can be either of the following,
A) okay. i will get u in touch with my parent.
B) i will treat u. (argument by child here would be if he can handle fat person he can surely handle thin person, if age is not a problem, as specification 8 )
The reason might be practical one, child want to be more famous or he has a chance to be loyal to his parent.
Analogy to java code:
When we swap doIt(char) and doIt(int) in parent and child,
Parent p = new Child();
p.doIt('R');

So, this was really a damn good question. i loved this one. i wish i had "more" similies to express myself
regards
maulin.
 
patrick tang
Ranch Hand
Posts: 44
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
really interesting question. it looks like a late-binding question to me at first, but turns out to be not.
 
Greenhorn
Posts: 16
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just to clarify,
1. cannot be overloading since doIt is in
separate classes
2. cannot be overriding since the signature
for doIt is different (re: parameter list)
in the superclass and subclass. This
implies that polymorphism (dynamic binding)
cannot be established.
Therefore, the type of the variable will
determine which method is called. Since
the variable is of type Parent, the method
in Parent is called.
 
patrick tang
Ranch Hand
Posts: 44
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
it makes sense now. thanks robert.
 
Jose Botella
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
to Robert
JLS 8.4.7 says


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 different signatures, then the method name is said to be overloaded . This fact causes no difficulty and never of itself results in a compile-time error. There is no required relationship between the return types or between the throws clauses of two methods with the same name but different signatures.

 
Rob Ross
Bartender
Posts: 2205
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, the lightbulb has gone off in my head. I think I can summarize this issue like this:
When the subject is method overriding, the compiler knows at *compile* time the method signature. It's just up to the runtime system to actually dispatch a method call to the right version based on the actual object instance.
When the subject is method *overloading* it has nothing to do with run-time type dispatch and everything to do with the compiler finding a method with that signature and binding that signature to a method call based on the object reference. If it can't completely, unambiguously determine the signature you'll get a compiler error; at worst, it will in fact determine which method signature it's going to use whether or not it's the one you really "wanted."

Rob
 
Jose Botella
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator


When the subject is method overriding, the compiler knows at *compile* time the method signature.


The method signature of the method that will be called? Well the signature yes, but the proper method called, is not untill runtime that this information is found out.
I think is easy to understand if we think that static, private anf final methods are bound statically. That means the method to be called is on the type of the variable that was used for the invocation.
Non private, non final instance methods are bound dinamically. The method called is in the type of the object pointed to by the variable used in in the method call.
 
Rob Ross
Bartender
Posts: 2205
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

The method signature of the method that will be called? Well the signature yes, but the proper method called, is not untill runtime that this information is found out.


Originally posted by Rob Ross:

When the subject is method overriding, the compiler knows at *compile* time the method signature.
***It's just up to the runtime system to actually dispatch a method call to the right version based on the actual object instance.***


Yes, I took that into account. I meant that at compile time, the
signature of the method is completely determined and that is "locked in". If the method is overridden then yes, the run-time system must find the right version of the method with that signature to invoke based on the actual instance, but the signature is already determined.
 
Ranch Hand
Posts: 464
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jose..
"Searching Child for methods named doIt result in
char doIt(int i) //declared in Child
char doIt(char i) //inherited from Parent
both are aplicable because 'R' can be converted to int without explicit cast. Which one will be chosen? JLS 15.12.2.2 will explain that:
We need to find the most specific method of both and that will be the winner.
char is widenning convertible to int, not the other way. Thus the method inherited from parent has one point. However we need to consider now the classes that declared both doIt methods. Child is widenning convertible to parent, not the other way. So the method declared in Child has another point.
There is a draw here. None of the methods are more specific than the other and the compiler will complain.
Search the Ranch for more examples about ambigous calls. "

Is char doIt(char i)more specific than the other one? Besides, there is no compilation error iin this code for ambiguity based reasons....
A famous code snippet comes to my mind

Even though both are applicable, runtime picks up the method based on the specificity
NOW..
I made few changes to this famous code..

When we run this code, it is now evident that Object version gets called not the string version even though, string version is more appropriate...
So in my humble opinion, i believe When a situation like this arises, where the programmer gives java a hard time(like this pseudo-ambigious calls), the method invocation becomes a static..(ie like Jose mentioned, reference based invocation, rather than dynamic lookup invocation or overloading...)

Ranchers, please post you comments , thoughts..
Ragu
[ January 12, 2002: Message edited by: Ragu Sivaraman ]
 
Jose Botella
Ranch Hand
Posts: 2120
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello Ragu
You have missed the point in JLS 15.12.1. The class to search for methods declarations is the type of the reference on which the method was called. In Big class there is only one method defined. The one that gets called. Besides that method is not overriden in the subclass.
 
Rob Ross
Bartender
Posts: 2205
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Right, this is an issue about overloading, NOT overriding. There is NO overriding going on here. The two methods have different signatures so there is no overriding .
When the compiler sees this code:
Big f = new Famous();
f.foo(null);
it checks the Big class for the appropriate method, and finds ONLY this method signature:
public void foo(Object o)
So it creates bytecode that makes a method invocation to a method with this signature. It's *always* going to call a method foo that takes an Object as an argument, nothing else.
At runtime, since there is no such method in the actual Famous instance that takes an Object argument, it uses the inherited version from Big.
Again, there is NO OVERRIDING going on here!!!
Rob

[ January 12, 2002: Message edited by: Rob Ross ]
 
Ranch Hand
Posts: 18944
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The following is my thought:
This is about compile-time and run-time.
During compile-time, the program looks for the appropriate method in Child since p is a windened Child. But the run-time determines which method to invoke, run-time finds p actually is a reference to a Parent object, and it finds there is a method called DoIt() in Parent, then it just
use "coercion" to coerce the char into an int, and
stop looking.
I believe this is still overriding even though
the apparent signatures are different, but conversion makes them the same. Thus, this is still one kind of dynamic binding.
my 2 cents
[ January 12, 2002: Message edited by: victor gu ]
 
patrick tang
Ranch Hand
Posts: 44
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
just to clarify. it's not overriding.
according to jls 8.4.6.1


An instance method m1 declared in a class C overrides another method with the same signature, m2, declared in class A if both
C is a subclass of A.
Either
m2 is non-private and accessible from C, or
m1 overrides a method m3, m3 distinct from m1, m3 distinct from m2, such that m3 overrides m2.


so it means two methods must have the same name, parameter, and return type. it has nothing to do with parameter conversion.
try the following code

the output is
Int Version in Child
S
because it's overriding, in runtime the actual object type is used, not the reference type.
moreover, in the method invocation alone, the actual parameter type should be convertible to the formal parameter type. so it will give a compile time error if you say p.doIt(10L).
in conclusion, if there's overloading not overriding, method invocation always depends on the reference type, because overloading method is just like a new method. even if Child inherites a Parent method, this method still belongs to Parent unless Child defines its own same method to override it.
pls correct me if i'm wrong as you know jls is really hard to understand

[ January 12, 2002: Message edited by: patrick tang ]
[ January 12, 2002: Message edited by: patrick tang ]
 
Anonymous
Ranch Hand
Posts: 18944
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Patrick:
You gave a very good explanation and a very good example. But I am still a bit confused about your
theory on run-time method invocation concerning
overloading or overriding. Maybe you are right,
maybe its a conclusion that can only be explained
if we look into java compiler. I guess I just have to remember it.
cheers

victor
 
patrick tang
Ranch Hand
Posts: 44
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hi victor,
pls refer to jose's previous post as follows


Let's see this invocation:
"System.out.println(p.doIt('R'));"
Always start the search for a method declaration in the type of the reference used in the call. That is Parent. There is a method in Parent
"char doIt(int i)"
Now is time to question is it a (non private, non final) instace method? Yes it is. Thus it could have been overriden. For determining whether a derived method should be called search the type of the instance holded by p. That is search Child for an overriding method. There is no one, so the Parent method is called.


its really a good explanation. it means first check reference type, then check if there's any overriding; if any overriding, check the actual object type to decide which method to call(polymorphism).
again, in my previous code, why not invoke seemingly more specific overloading method "char doIt(char c)" in Child class? because of "Parent p = new Child()". reference type is Parent and actual object type is Child. as both classes have the same method "char doIt(int i)", it's overriding. in runtime, Child's method is called because the actual object is Child. Child's "char doIt(char c)" will not be called as its not the overriding method, even though it's really more specific. you may call it using "Child c = new Child(); c.doIt('R')" and then it's overloading and more specific one is invoked.
hope it's clear...
 
CLUCK LIKE A CHICKEN! Now look at this tiny ad:
Rocket Oven Kickstarter - from the trailboss
https://coderanch.com/t/695773/Rocket-Oven-Kickstarter-trailboss
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!