scalagenericstypesscala-genericstype-members

type parameter with underlying type in - Scala


Lets say I've a trait with a type A that is a subclass of Any and a method called nextState that has that same type as a parameter.

trait GameEnvironment {
  type A <: Any
  def nextState(state: A, input: Int): (A, Boolean)
}

This trait is then extended by a class called Tetris that overrides the type member A and the method nextState.

class Tetris extends GameEnvironment {
  override type A = ((Array[Array[Int]]), Int)

  def nextState(state: (Array[Array[Int]], Int), input: Int): 
  ((Array[Array[Int]], Int), Boolean) = {


     ((state, false))
  }
}

Now in another class called ReinLib I create a GameEnvironment, and I also have a function that takes in a parameter GameEnvironment#A.

class ReinLib(val mode: String) {
  val env : GameEnvironment = new Tetris()

  def simulateStep(state: GameEnvironment#A, input: Int): (Boolean) = 
    {
       env.nextState(state, input)._2
    }
}

Now if I compile this code I get an error

type mismatch state.type (with underlying type...

From what I gather this happens since the compiler is not certain which type state has. However I could not seem to find how to solve my issue, so I'm wondering how one would get around this.


Solution

  • The type GameEnvironment#A is way too vague, it is essentially completely unrelated to the type of state used in env.

    You probably want something like this:

    trait GameEnvironment {
      type A
      def nextState(state: A, input: Int): (A, Boolean)
    }
    
    class Tetris extends GameEnvironment {
      override type A = ((Array[Array[Int]]), Int)
    
      def nextState(state: A, input: Int): (A, Boolean) = {
        (state, false)
      }
    }
    
    class ReinLib(val mode: String) {
      val env: GameEnvironment = new Tetris()
    
      def simulateStep(state: env.A, input: Int): Boolean = {
        env.nextState(state, input)._2
      }
    }
    

    It compiles successfully, because now env.nextState can accept state: env.A as parameter.