Defining return values of the same class in interface implementations
hello,
i'm trying to update older code to java 1.5 using generics. i'm new to generics and i have a problem i cannot solve: assuming the interface
publicinterface Stake
{
public Stake makeACopyAndShift(long delta );
}
and the class
publicclass BasicStake
{
privatefinallong pos;
public BasicStake(long pos )
{
this.pos = pos;
}
public Stake makeACopyAndShift(long delta )
{
returnnew BasicStake( pos + delta );
}
}
... and a container class Trail:
publicclass Trail<S>{
privatefinal List<S> stakes =new ArrayList<S>();
public Trail(){}
publicvoid add( S stake ){ stakes.add( stake );}
public S get(int index ){return stakes.get( index );}
publicvoid shiftAll(long delta )
{
final List<S> stakesNew =new ArrayList<S>( stakes.size() );
S orig, copy;
for(int i = 0; i < stakes.size(); i++ ){
orig = stakes.get( i );
copy = (S) orig.makeCopyAndShift( delta );
stakesNew.add( copy );
}
stakes.clear();
stakes.addAll( stakesNew );
}
}
so that i could do:
Trail<BasicStake> t =new Trail<BasicStake>();
etc.
how do i manage to get rid of the warning
"Type safety: The cast from Stake to S is actually checking against the erased type Stake"
with casting to (S) in the for-loop in the shiftAll function? Obviously the problem is that in interface Stake the return type of makeCopyAndShift should not be Stake but "<SameClassAsMe>", so that in BasicStake the method would be
public BasicStake makeCopyAndShift(long delta ){ ...}
. how do i accomplish that?
thanks a lot!
ciao, -sciss-
# 1
Something like this if I'm not mistaken:
public class Trail<S extends Stake> {
private final List<Stake> stakes;
public Trail() { stakes = new ArrayList<Stake>(); }
public void add(S stake) { stakes.add(stake); }
public Stake get(int index) { return stakes.get(index); }
public void shiftAll(long delta) {
final List<Stake> stakesNew = new ArrayList<Stake>(stakes.size());
for(int i = 0; i < stakes.size(); i++ ) {
Stake orig = stakes.get(i);
Stake copy = orig.makeACopyAndShift(delta);
stakesNew.add(copy);
}
stakes.clear();
stakes.addAll(stakesNew);
}
}
# 2
but the whole idea is to be dealing with special cases of Stake, so i definitely want
private final List<S> stakes;
and
public S get( int index ) { return stakes.get( index ); }
... otherwise there's no point in using generics.
# 3
This seems to work just fine for me:
public class Foo {
public static void main(String[] args) {
Trail<Stake> trail = new Trail<Stake>();
trail.add(new BasicStake(1));
trail.add(new AnotherStake(1));
trail.shiftAll(10);
}
}
interface Stake {
public Stake makeACopyAndShift(long delta);
}
class BasicStake implements Stake {
private final long pos;
public BasicStake(long pos) {
this.pos = pos;
}
public Stake makeACopyAndShift(long delta) {
return new BasicStake(pos+delta);
}
}
class AnotherStake implements Stake {
private final long pos;
public AnotherStake(long pos) {
this.pos = pos;
}
public Stake makeACopyAndShift(long delta) {
return new AnotherStake(pos*delta);
}
}
class Trail<S extends Stake> {
private final List<Stake> stakes;
public Trail() { stakes = new ArrayList<Stake>(); }
public void add(S stake) { stakes.add(stake); }
public Stake get(int index) { return stakes.get(index); }
public void shiftAll(long delta) {
final List<Stake> stakesNew = new ArrayList<Stake>(stakes.size());
for(int i = 0; i < stakes.size(); i++ ) {
Stake orig = stakes.get(i);
Stake copy = orig.makeACopyAndShift(delta);
stakesNew.add(copy);
}
stakes.clear();
stakes.addAll(stakesNew);
}
}
# 4
but
Trail<Stake> trail = new Trail<Stake>();
doesn't make sense, i wouldn't need generics to do that. this will not work:
Trail<BasicStake> trail = new Trail<BasicStake>();
trail.add( new BasicStake( 1 ));
BasicStake x = trail.get( 0 );// > fails
# 5
> but
>
> Trail<Stake> trail = new Trail<Stake>();
>
> doesn't make sense, i wouldn't need generics
> to do that. this will not work:
>
> Trail<BasicStake> trail = new Trail<BasicStake>();
> trail.add( new BasicStake( 1 ));
> BasicStake x = trail.get( 0 );// > fails
Ah yes, I see what you mean.
What I do know is that you should bound that S in your Trail class so that it is a Stake.
I'm sure there will be someone along that knows some Java-generics (unlike me!).
; )
# 6
Why don't you do some work yourself and adapt what's there?class Trail<S extends Stake> {
private final List<S> stakes;
public Trail() { stakes = new ArrayList<S>(); }
public void add(S stake) { stakes.add(stake); }
public S get(int index) { return stakes.get(index); }
public void shiftAll(long delta) {
final List<S> stakesNew = new ArrayList<S>(stakes.size());
for(int i = 0; i < stakes.size(); i++ ) {
S orig = stakes.get(i);
S copy = orig.makeACopyAndShift(delta);
stakesNew.add(copy);
}
stakes.clear();
stakes.addAll(stakesNew);
}
}
Where "makeACopyAndShift" should return the proper type (co-variant return).
# 7
thank you, i didn't know overriding return values in implementing classes was allowed (what you coin "co-variant return"), that seems to be exactly what i need.
ciao, -sciss-.
# 8
> thank you, i didn't know overriding return values in
> implementing classes was allowed (what you coin
> "co-variant return"), that seems to be exactly what i
> need.
Ah, OK. So your OP was a case of information overflow wrt. the actual problem. :)
# 9
Can you complete the example? It is not clear to me how to utilize covariant return in this case. I have the following solution which works with the Trail class provided, but I think you mean something different.
interface Stake<S> {
public S makeACopyAndShift(long delta);
}
class BasicStake implements Stake<BasicStake> {
...
public BasicStake makeACopyAndShift(long delta) {
return new BasicStake(pos + delta);
}
}
# 10
Actually in my solution I had to change Trail class. It looks like this:
interface Stake<S> {
public S makeACopyAndShift(long delta);
}
class BasicStake implements Stake<BasicStake> {
private final long pos;
public BasicStake(long pos) {
this.pos = pos;
}
public BasicStake makeACopyAndShift(long delta) {
return new BasicStake(pos + delta);
}
}
class Trail<S extends Stake><S>> {
private final List<S> stakes;
public Trail() { stakes = new ArrayList<S>(); }
public void add(S stake) { stakes.add(stake); }
public S get(int index) { return stakes.get(index); }
public void shiftAll(long delta) {
final List<S> stakesNew = new ArrayList<S>(stakes.size());
for(int i = 0; i < stakes.size(); i++ ) {
S orig = stakes.get(i);
S copy = orig.makeACopyAndShift(delta);
stakesNew.add(copy);
}
stakes.clear();
stakes.addAll(stakesNew);
}
}
# 11
No generics involved with co-variant return.
interface Stake { // no generics here!
public Stake makeACopyAndShift(long delta);
}
class BasicStake implements Stake {
...
public BasicStake makeACopyAndShift(long delta) {
return new BasicStake(pos + delta);
}
}
# 12
I am sorry, but I still do not understand how it all plays together. What about generic Trail class?