Generics: how to avoid overloaded methods?

  • Thread starter Michael Borgwardt
  • Start date
M

Michael Borgwardt

I'm currently using generics quite intensively and have run into a problem with
the following configuration:

class DataBase{}
class DataSub extends DataBase{}

class ControllerBase<D extends DataBase>{
void method(D d);
}

class ControllerSub<D extends DataSub> extends ControllerBase<D>{
void method(D d);
}

My Problem is I think that, due to type erasure, method() in ControllerSub
does not override method() in ControllerBase, it overloads it, i.e.:

class ControllerBase{
void method(DataBase d);
}

class ControllerSub extends ControllerBase{
void method(DataSub d);
}

The result is that client classes that know only about ControllerBase end up
calling method(DataBase) even when doing it with an instance of DataSub
through an instance of ControllerSub.

Any idea how to avoid this and still keep the type safety Generics provide as
much as possible?
 
J

John C. Bollinger

Michael said:
I'm currently using generics quite intensively and have run into a
problem with
the following configuration:

class DataBase{}
class DataSub extends DataBase{}

class ControllerBase<D extends DataBase>{
void method(D d);
}

class ControllerSub<D extends DataSub> extends ControllerBase<D>{
void method(D d);
}

My Problem is I think that, due to type erasure, method() in ControllerSub
does not override method() in ControllerBase, it overloads it, i.e.:

class ControllerBase{
void method(DataBase d);
}

class ControllerSub extends ControllerBase{
void method(DataSub d);
}

For what it's worth, javap confirms your hypothesis.
The result is that client classes that know only about ControllerBase
end up
calling method(DataBase) even when doing it with an instance of DataSub
through an instance of ControllerSub.
Any idea how to avoid this and still keep the type safety Generics
provide as
much as possible?

I don't see a way to cause ControllerSub.method(D') to override
ControllerBase.method(D) while still exposing the narrower type to
ControllerSub.method's body. Perhaps, then, it is useful to fall back
on a tried and true typesafe mechanism such as the Visitor pattern
(a.k.a. double dispatch). It is conceivable that you could even use the
observed overloading behavior in your favour in such a scenario,
although I haven't worked out quite how that would work just yet.


John Bollinger
(e-mail address removed)
 
C

Chris Uppal

Michael said:
class DataBase{}
class DataSub extends DataBase{}

class ControllerBase<D extends DataBase>{
void method(D d);
}

class ControllerSub<D extends DataSub> extends ControllerBase<D>{
void method(D d);
}

Not an attempt to answer your question, Michael. I just wondered if I was
alone in finding the above sketch almost impossible to "feel" ?

Put another way: is it just that I'm not used to (Java) generics yet, or is the
above genuinely hard to understand (significantly so) ?

-- chris
 
M

Michael Borgwardt

Chris said:
Not an attempt to answer your question, Michael. I just wondered if I was
alone in finding the above sketch almost impossible to "feel" ?

Put another way: is it just that I'm not used to (Java) generics yet, or is the
above genuinely hard to understand (significantly so) ?

Probably a combination of both. Generics definitely seems to get really nasty really
quickly as soon as inheritance is involved.

I've thought about the example a bit, and I think the functionality is better
represented through delegation rather than inheritance, and perhaps accessed
through a generic interface.
 
N

Neal Gafter

Your analysis is incorrect. ControllerSub.method does indeed override
ControllerBase.method. javap is showing you the details of how the
javac accomplishes that, but you didn't bother to examine the
implementation of those methods to see the rest of the story.

In short, overriding for examples like these work exactly as you would
expect. Erasure has nothing to do with it.
 
M

Michael Borgwardt

Neal said:
Your analysis is incorrect. ControllerSub.method does indeed override
ControllerBase.method. javap is showing you the details of how the
javac accomplishes that, but you didn't bother to examine the
implementation of those methods to see the rest of the story.

Oooh I see:

class gen.ControllerSub extends gen.ControllerBase{
gen.ControllerSub();
Code:
0: aload_0
1: invokespecial #9; //Method gen/ControllerBase."<init>":()V
4: return

void method(gen.DataSub);
Code:
0: return

void method(gen.DataBase);
Code:
0: aload_0
1: aload_1
2: checkcast #25; //class gen/DataSub
5: invokevirtual #27; //Method method:(Lgen/DataSub;)V
8: return

}

But that's cheating! Well, all of Generics is...
In short, overriding for examples like these work exactly as you would
expect. Erasure has nothing to do with it.

I'm not sure anymore what behaviour caused me to start thinking otherwise.
It may have been a problem with the incomplete Generics support in eclipse 3.1M2
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top