Cyclic generics

I am trying to do something like:

public interface Player<R> { R takeTurn(Game game); } 

and

 public interface Game { } public class XPlayer implements Player<Interger> { // XGame won't work because the interface takes Game public Integer takeTurn(final XGame game) { return (null); } } public class XGame { } 

What I'm stuck with is what I need to change in the Game and Player interfaces in order to get the generics to work (I paused while I still have hair in my head :-) In particular, I hung up, the player must know the type of game, and the game must know the type of player.

0
source share
3 answers

This is not a general question ( Game not recruited).

This is a matter of inheritance. Try the following:

 public class XGame implements Game // added interface 
+6
source

So, we have a situation where we have games and players, and they can be subclasses. TicTacToe GAME uses TicTacToe PLAYERS and vica-versa.

To do this, put all classes in the declaration. The declaration ends incredibly ugly, but the code that uses it becomes very clean.

I like to keep the list of generic types in the same order in the class system that I use.

 abstract class Game<// G extends Game<G, P>, // P extends Player<G, P>> { P getCurrentPlayer() {return null;} } abstract class Player<// G extends Game<G, P>, // P extends Player<G, P>> { G getCurrentGame() {return null; } 

And you use these abstract classes as follows:

 class TTTGame extends Game<TTTGame, TTTPlayer> {} class TTTPlayer extends Player<TTTGame, TTTPlayer> {} class ChessGame extends Game<ChessGame, ChessPlayer> {} class ChessPlayer extends Player<ChessGame, ChessPlayer> {} 

etc. Strong typing means that a game of chess will play chess, and chess players will be chess players - in all types of return value, parameters and visible fields.

You can even do tricks, such as expanding the inheritance hierarchy in one way, but not in another. Suppose we have defined a class of games in which players only need to flip a coin and report heads or tails. We can create a coin player that works for any coingame, and a coin game, the type of which is still common, but which links P.

 class CoinGame<G extends CoinGame<G>> // extends Game<G, CoinPlayer<G>> { } class CoinPlayer<G extends CoinGame<G>> // extends Player<G, CoinPlayer<G>> { boolean flip() { return true; }; } 

Coin game subclasses have only one type parameter, because they all take coin type players. Most specific games will associate this parameter with themselves:

 class DontFlipHeads // extends CoinGame<DontFlipHeads> { class YouLose extends Exception { } void turn() throws YouLose { if (getCurrentPlayer().flip()) throw new YouLose(); } } 

The DontFlipHeads class knows that its player has a flip method, since it extends the game that binds the type of player that has this method, although getCurrentPlayer () is defined in common law at the bottom of the inheritance hierarchy.

Note that there must be a parameter for the DontFlipHeads player class. In this way:

 … DontFlipHeads game = new DontFlipHeads(); CoinPlayer<DontFlipHeads> player1 = new CoinPlayer<DontFlipHeads>(); game.addPlayer(player1, 1); 

This would not be necessary if there were no two-way link. But since there is a link, you can

 DontFlipHeads whatGame = player1.getGame(); 

without casting.

+1
source

Why not have something like this -

  public Integer takeTurn(Game game) { XGame xGame = (XGame) game; // assuming XGame implements Game return ...; } 
0
source

All Articles