473,320 Members | 1,930 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,320 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 2207

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: ryjfgjl | last post by:
ExcelToDatabase: batch import excel into database automatically...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Defcon1945 | last post by:
I'm trying to learn Python using Pycharm but import shutil doesn't work
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

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.