473,387 Members | 1,904 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,387 software developers and data experts.

which foo(x)

I was trying to write some polymorphic application code and found that
a superclass method implementation gets invoked when I expect a
subclass implementation. Here's how I have abstracted the problem.

I have a base class - ClassA. I have a subclass of ClassA - ClassB.
Both classes implement foo() - exact same method signature.

My application code instantiates instances of ClassB (and siblings)
via a marshaler, and only knows that the object it references is a
"kind of" ClassA. I simulate this as shown below.

ClassA a = (ClassA) Class.forName("ClassB").newInstance();

Now, if I send a.foo(), I see that the implementation overriden in
ClassB is invoked - as I had hoped and expected.
But really what I am aiming for is something with a different twist.

I have another class hierarchy with a base class - ClassX - and a
subclass - ClassY.

I have implemented ClassA.foo(ClassX) and ClassB.foo(ClassY).

Instances of ClassX and ClassY are created outside the context of the
code that invokes foo(...). All this code knows is that it's got a
reference to an object which is a "kind of" ClassX. I simulate this as
shown below.

ClassX x = (ClassX) Class.forName("ClassY").newInstance();

If, in this scenario, I send a.foo(x) I see that it is the super
implementation of foo(...) that is invoked rather than the subclass
implementation of foo(...).

This was a big surprise to me. And it may seem as puzzling to some
that I found it surprising. After all, you note, the Java compiler
chose exactly the right implementation based on the information that I
provided.

I can kind of accept this, although I would argue that this behavior
makes polymorphic code really fragile and difficult to debug, since
runtime behavior is different from the language semantics due to ...
?compiler optimization?. (Coming to Java from a Smalltalk background,
as I do, the complexity here seems a bit bizarre)

But wait. By this reasoning, shouldn't I have gotten the superclass
implementation of foo(void) in the first scenario?

Just by way of exploring this puzzle a little further, I added another
scenario. Suppose I have a variable declared as "ClassB b", and send
"foo(x)" (where, as above 'x' is an instance of ClassY). This is at
least consistent with scenario #2 - I get the super implementation
because the compiler doesn't know that 'x' is actually a reference to
an instance of ClassY.

So far, then, it seems like scenario #1 is a bug, since - although
it's what I wanted - it's inconsistent with the other two scenarios.
Is there another explanation?

-rht

public class Testcase5 {

public static void main(String argv[]) {
ClassA a;
ClassB b;
ClassX x;
try {
a = (ClassA) Class.forName("ClassB").newInstance();
b = (ClassB) Class.forName("ClassB").newInstance();
x = (ClassX) Class.forName("ClassY").newInstance();
} catch (Exception e) {
System.err.println(e.getMessage());
return;
}

b.foo(); // out: "B.foo()"
a.foo(); // out: "B.foo()"

b.foo(x); // out: "A.foo(x)"
a.foo(x); // out: "A.foo(x)"
}
}
Jul 17 '05 #1
2 2210

Hi,

(Sorry for this late answer, I'm not reading the forum regularly)
I was trying to write some polymorphic application code and found that
a superclass method implementation gets invoked when I expect a
subclass implementation. Here's how I have abstracted the problem.


You did a good analysis of the situation of Java. The key you seem to
miss to understand the "logics" behind Java's behaviour is the
following. In Java, a method call is of the form
x.meth(a);
meth is a method name, and x is call the receiver of the call. There
could be more than one argument a, but it does not matter here.
The way the code to execute for this call is like this:
1) during compilation, the compiler looks at the (static) type of a,
and looks in the class C which is the (static) type of x a method with
the name "meth" that matches the type of a (not relevant, but for the
sake of completeness: it also consider methods defined in super-classes
of C, and if there are more than one possible method, it will choose the
most specific). Let's call the result of this search method M.
2) during execution, there is a mechanism to "refine" this search, by
looking at the actual class of the object that x represents. It is sure
that this class is either C, or a subclass of C. If it is a subclass D,
then a method with the same signature as M might have been defined in D,
or somewhere between C and D. In that case, that method will be called,
not M. However, if a method has a more precise signature than M because
it handles only a subclass of the original class for the argument, it is
not considered, even when this more precise method would be applicable
to the runtime argument of the call. It is this last situation that
surprised you in your example.

So you can see that there is a fundamental asymetry in a method call:
the type of the receiver will be checked during execution to find a more
precise method, but not the types of the arguments.

The behaviour of Java, C++, Eiffel and most object-oriented languages is
called "single dispatch" because they dispatch (choose the method to
execute) based on the type of a single argument. A few other OO
languages use "multiple dispatch", because, you guessed it, they use the
type of multiple arguments to decide what method to execute. To name a
few: Cecil, Dylan, CLOS. I am myself the main designer of a language
called Nice, which is a variation on Java that supports multiple
dispatch. For instance, thanks to multiple dispatch, you can write in Nice:

class Point
{
private int x;

equals(Point that) {
return this.x == that.x;
}
}

while Java programmers need to write:

class Point
{
private int x;

public boolean equals(Object that) {
if (that instanceof Point) {
Point thatPoint = (Point) that;
return this.x == thatPoint.x;
} else {
return super.equals(that);
}
}
}

Both codes are stricly equivalent, but I believe the Nice version is
easier to write and to read ;-)

If you want to find out more, Nice's homepage is http://nice.sf.net

Daniel

Jul 17 '05 #2
Daniel,

Thanks for your response.

With the help of the responses to my posting, I have worked my way
towards a rationalization of this behavior.

At compile time I indicated that I wanted the method with signature
foo(ClassX) to be invoked. In implementing ClassB.foo(ClassY) I was
thinking that I was overriding ClassA.foo(ClassX).

Sloppy thinking on my part. Conceptually, the latter cannot be an
override of the former precisely because it is more restrictive. (I
suppose I was expecting the runtime to treat it as an override when it
"could" be treated as such.) Moreover, the latter has no special
relationship in Java to the former at all; it is simply a different
method with the same name.

The fact that Java allows me to reuse the name in this scenario (where
ClassY extends ClassX) is what I would call a "pitfall", because my
mistake seems to me like an easy mistake to make.

So I need to train myself to do something like what's done in your
Point example. Implement a method with precisely the the same
signature, test the argument and cast or delegate to super as
appropriate.

Thanks,

-Rick
Daniel Bonniot <Da************@inria.fr> wrote in message news:<3F**************@inria.fr>...
while Java programmers need to write:

class Point
{
private int x;

public boolean equals(Object that) {
if (that instanceof Point) {
Point thatPoint = (Point) that;
return this.x == thatPoint.x;
} else {
return super.equals(that);
}
}
}

Jul 17 '05 #3

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Rick Trotter | last post by:
I was trying to write some polymorphic application code and found that a superclass method implementation gets invoked when I expect a subclass implementation. Here's how I have abstracted the...
6
by: Victor Ng | last post by:
I'm doing some evil things in Python and I would find it useful to determine which class a method is bound to when I'm given a method pointer. For example: class Foo(object): def...
12
by: Me | last post by:
Hi, I would like learn from people with experience in C++, which of the following styles of way to construct "get/set" member functions would be the best in terms of usability, speed, et cetera. ...
3
by: wogston | last post by:
(A) template <typename T> metainline foo<T> lerp(const foo<T>& a, const foo<T>& b, const T& time) { foo<T> v; repeat< 4,exec_mul<T> >::exec(v,a,b,time); return v; }
2
by: Jonathan Turkanis | last post by:
Hi All, The simple test program at the end of this message defines a class template foo with a member function bar implemented by delegating to a static member function of a specialization of...
2
by: Csaba | last post by:
I have a class which contains an integer acting as a bit map (i.e. individual bits have separate meanings) union foo { int integer_; struct{ /* here be bitfields */ } parts_; foo( int i ) :...
52
by: Darklight | last post by:
Question: Write a function named sumarrays() that accepts two arrays that are the same size. The function should add each element in the array together and place the values in the thrid array. ...
19
by: Geetesh | last post by:
Recently i saw a code in which there was a structer defination similar as bellow: struct foo { int dummy1; int dummy2; int last }; In application the above array is always allocated at...
2
by: kids_pro | last post by:
Hi there, When class construct it read content from XML file and store it in ArrayList. In my class I had implement Search method using BinarySearch behind. I want to implement another Method...
37
by: C_guy | last post by:
Does anyone know of a (hopefully free) tool that can traverse a project and determine which "#include"s are not needed or needed in every .C file? This would be helpful in removing header...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.