Second attempt at this question (the initial code wasn't enough to highlight the issue)
Here is the code that does not compile:
interface Player<R, G extends Game>
{
R takeTurn(G game);
}
interface Game<P extends Player>
{
void play(P player);
}
abstract class AbstractGame<R, P extends Player>
implements Game<P>
{
public final void play(final P player)
{
final R value;
value = player.takeTurn(this);
turnTaken(value);
}
protected abstract void turnTaken(R value);
}
public class XPlayer
implements Player<Integer, XGame>
{
@Override
public Integer takeTurn(final XGame game)
{
return (42);
}
}
public class XGame<P extends Player<Integer, XGame>>
extends AbstractGame<Integer, XPlayer>
{
@Override
protected void turnTaken(final Integer value)
{
System.out.println("value = " + value);
}
}
public class Main
{
public static void main(final String[] argv)
{
final XPlayer player;
final XGame game;
player = new XPlayer();
game = new XGame();
game.play(player);
}
}
What I am running up against is trying to get the play method in the AbstractGame to compile. It seems that I have to run in circles with the Game and the Player adding generics to the extends/implements but for the life of me I cannot get it straight.
The play method has to be final in the AbstractGame class, and there is no way to do casting, and I don't want to write another method like the turnTaken one to get it to work if I don't have to.
EDIT: as requested here is the code that compiles, but needs the cast:
interface Player<R, P extends Player<R, P, G>, G extends Game<R, G, P>>
{
R takeTurn(G game);
}
interface Game<R, G extends Game<R, G, P>, P extends Player<R, P, G>>
{
void play(P player);
}
abstract class AbstractGame<R, G extends Game<R, G, P>, P extends Player<R, P, G>>
implements Game<R, G, P>
{
public final void play(final P player)
{
final R value;
value = player.takeTurn((G)this);
turnTaken(value);
}
protected abstract void turnTaken(R value);
}
class XPlayer
implements Player<Integer, XPlayer, XGame>
{
@Override
public Integer takeTurn(final XGame game)
{
return (42);
}
}
class XGame
extends AbstractGame<Integer, XGame, XPlayer>
{
@Override
protected void turnTaken(final Integer value)
{
System.out.println("value = " + value);
}
}
class Main
{
public static void main(final String[] argv)
{
final XPlayer player;
final XGame game;
player = new XPlayer();
game = new XGame();
game.play(player);
}
}