This week's book giveaway is in the Design forum.We're giving away four copies of Design for the Mind and have Victor S. Yocco on-line!See this thread for details.
Win a copy of Design for the Mind this week in the Design forum!

# Covariant Return Types

Deepthi Kanakam Rajan
Greenhorn
Posts: 13
The following code:

class A
{
int x=5;
}

class B extends A
{
int x=6;
}

public class CovariantTest
{
public A getObject()
{
return new A();
}

public static void main(String args[])
{
CovariantTest c1 = new SubCovariantTest();

System.out.println(c1.getObject().x);
}
}

class SubCovariantTest extends CovariantTest
{
public B getObject()
{
return new B();
}
}

The answer given is 5 though i feel is should have been 6.

Ranch Hand
Posts: 65
The "int x" declaration in class B "shadows" the one in class A, and thus does NOT participate in the inheritance.

If class B simply inherited "x" instead of declaring its own version, the result would be what you had expected.

wise owen
Ranch Hand
Posts: 2023

Ranch Hand
Posts: 65
Sorry, but the explanation provided in that link is wrong. This issue has nothing to do with covariant returns really.

For example, if we modify SubCovariantObj.getObject() to return A instead of B (so there is no covariant return at all), the answer would still be the same.

wise owen
Ranch Hand
Posts: 2023

Sai Surya
Ranch Hand
Posts: 463
The correct answer I believe is OVERRIDING will NOT be applied to variables. What variable to access in the above case is decided based on Reference type and NOT on actual type.

Try adding code to return x, like int getX() { return x; } in each class A and B, and call that getX() instead of directly showing x, it will print 6.

- Surya.

Ranch Hand
Posts: 65
Right!

wise owen: Try it yourself. Modify SubCovariantObj.getObject() to return A instead of B, i.e., "public A getObject()", so there is no covariant return, and therefore no "synthetic bridge".

How come the result is still the same? Because covariant returns has nothing to do it this issue!

wise owen
Ranch Hand
Posts: 2023
Instance variables, static variables, static overridden methods (it looks like it's an override, but actually hidden), and overloaded methods are all bound at compile time.

Compiler need to know what "c1.getObject()" is for "x". Calling getX() is Run time binding and this kind of binding depends on the instance object type.

Burkhard Hassel
Ranch Hand
Posts: 1274

Sorry, but the explanation provided in that link is wrong. This issue has nothing to do with covariant returns really.

Well it has. And it has nothing to do with shadowing.
If you have
CovariantTest c1 = new SubCovariantTest();
in the main method, and you call
getObject()
on c1, then the synthetic bridge (see link of wise) will come into play.

The object returned by getObject will be an A, not a B.
The code will not compile if you add
B test = c1.getObject();

A test = c1.getObject();
would be fine.

Yours,
Bu.

Ranch Hand
Posts: 65
Then please explain why the code below, which has NO covariant return, and therefore no bridging method whatsoever, still return the SAME result.

You can't have it both ways.

Keith Lynn
Ranch Hand
Posts: 2409
Then please explain why the code below, which has NO covariant return, and therefore no bridging method whatsoever, still return the SAME result.

You can't have it both ways.

Because the method you provided has the same return type as the bridge method.

This is the result of javap on the original SubCovariantTest.

Ranch Hand
Posts: 65
Nah, the modified example I provided above would return the same result even under JDK 1.4. :roll:

The behavior hasn't much to do with covariant returns, then, obviously if the same exact result can be obtained: a) when covariant return is used; b) when covariant returned is not used; and c) under a JDK when covariant returns didn't even existed.

Keith Lynn
Ranch Hand
Posts: 2409
But the SubCovariantTest program wouldn't compile under 1.4.

Burkhard Hassel
Ranch Hand
Posts: 1274
Hi ranchers,

Nah, the modified example I provided above would return the same result even under JDK 1.4.

Your example is irrelevant as there are only A reference types returned.
The real question is, what the lines

do.

The real question is: What will c1.getObject() return, an A or a B?
I'm speaking about reference type (or compile type), not about the type of the object. And reference type surely is a matter of covariance.

The key is, that c1.getObject() returns an A-type and not a B-type as you would expect in the first place.
I said it again, try

after the above lines.
It will not compile, as the super class A will be returned.

The fact that

will produce two fives has never been debated.

Yours,
Bu.

Ranch Hand
Posts: 65
I guess we can agree to disagree. My last reply to this topic.

I leave you with a piece of code below... which is ALL that is actually happening. The rest of the fluff (covariant, bridging, etc.) are simply red-herrings. Feel free to use any JDK.

Result: 5

Keith Lynn
Ranch Hand
Posts: 2409
I fail to see the relevance of that code. You're simply demonstrating that instance variables are hidden, not overridden.

Ranch Hand
Posts: 65
Ooops, sorry Burkhard replied while I was typing.

Burkhard: you write "The key is, that c1.getObject() returns an A-type and not a B-type as you would expect in the first place."

No, in fact c1.getObject() returns a B-type, as one would normally expect. Please verify this yourself.

Burkhard Hassel
Ranch Hand
Posts: 1274
... which is ALL that is actually happening. The rest of the fluff (covariant, bridging, etc.) are simply red-herrings. Feel free to use any JDK.

Yep!

;-)

Bu.

Burkhard Hassel
Ranch Hand
Posts: 1274
No, in fact c1.getObject() returns a B-type, as one would normally expect. Please verify this yourself.

c1.getObject returns an object of type B, whose reference type is A (and not B).
This can be stored into reference type Object, sure.
And prints out B@hash something, sure.

But

Compiler says:

The second line cannot compile, because the reference type of c1.getObject() is A.
The last line compiles, cause the object returned here is of reference type A, with an object type of B. But that the object type is B was also printed out in Ade's code above already.
And never been debated, as the output of the original post (see way above) depends only on the reference type, not the object type.

Yours,
Bu.