Strange Scala Error

I tried to create an abstract turn-based game and abstract AI:

abstract class AGame { type Player type Move // Player inside def actPlayer : Player def moves (player : Player) : Iterator[Move] def play (move : Move) def undo () def isFinished : Boolean def result (player : Player) : Double } abstract class Ai[Game <: AGame] { def genMove (player : Game#Player) : Game#Move } class DummyGame extends AGame { type Player = Unit type Move = Unit def moves (player : Player) = new Iterator[Move] { def hasNext = false def next = throw new Exception ("asd") } def actPlayer = () def play (move : Move) { } def undo () { } def isFinished = true def result (player : Player) = 0 } class DummyAi[Game <: AGame] (game : Game) extends Ai[Game] { override def genMove (player : Game#Player) : Game#Move = { game.moves (player).next } } 

I thought that I needed to use this strange type of accessors, for example Game # Player. I get a very mysterious error. I would like to understand this:

 [error] /home/lew/Devel/CGSearch/src/main/scala/Main.scala:41: type mismatch; [error] found : Game#Player [error] required: DummyAi.this.game.Player [error] game.moves (player).next [error] ^ 
+4
source share
2 answers

def moves (player : Player) means that moves accepts a player for this Game .

Game#Player is the type of player of any Game . Thus, moves (player) is a type mismatch.

Here is a simple example that shows why this should be a mismatch. Suppose this is not the case and see what happens next:

 class Game2 extends DummyGame { override type Player = Boolean override type Move = Boolean override def moves(player : Boolean) = new Iterator[Boolean] {...} } val game2: DummyGame = new Game2 // game2.Player is Boolean val dummyGameAi = new DummyAi[DummyGame](game2) // DummyGame#Player == Unit, so the type of genMove for Ai[DummyGame] is // def genMove (player : Unit) : Unit dummyGameAi.genMove(()) // this calls game2.moves(()), which doesn't typecheck 

For this to work, we can change the genMove type. If we pass the game as an argument (and that makes sense anyway), we can use path-dependent types:

 abstract class Ai[Game <: AGame] { def genMove (game : Game)(player : game.Player) : game.Move // now game.moves (player) typechecks } 
+5
source

You can solve your problem by introducing the abstract element game in Ai , and then specify the type depending on the path using this element:

 abstract class Ai[Game <: AGame] { val game : Game def genMove (player : game.Player) : game.Move } class DummyAi[Game <: AGame] (val game : Game) extends Ai[Game] { override def genMove (player : game.Player) : game.Move = { game.moves (player).next } } 
+3
source

Source: https://habr.com/ru/post/1312693/


All Articles