MathFun
MathFun

Reputation: 13

Type mismatch for generic class method call

Please consider the following trivial example:

class C[P](val list: Seq[P]){
  def print(e: P){
    println(e)
  }
}

object Test{
  def g[P](c: C[P]) = {
    c.print(c.list(0))
  }

  def f(i: Int): C[_] = {
    i match {
      case 1 => new C(Seq(1, 2, 3))
      case _ => new C(Seq("A", "B", "C"))
    }
  }

  def main(args: Array[String]): Unit = {
    val c = f(1)
    g(c) // works
    c.print(c.list(0)) // does not work
  }
}

My question is, in the main function, why the first call compiles, but the second gives "type mismatch" error.

Is there any other (better) way to do what is intended here?

Edit 1:

According to the answer by @chengpohi, I can change the type of the returned value of f to C[Any], but this generally may not work. For example, if we change the code to

class B[P]

class BInt extends B[Int]

class BString extends B[String]

class C[P](val list: Seq[P], val obj: B[P]) {
  def print(e: P) {
    println(e)
  }
}

object Test {
  def g[P](c: C[P]) = {
    c.print(c.list(0))
  }

  def f(i: Int): C[_] = {
    i match {
      case 1 => new C(Seq(1), new BInt)
      case _ => new C(Seq("String"), new BString)
    }
  }

  def main(args: Array[String]): Unit = {
    val c = f(1)
    g(c) // works
    c.print(c.list(0)) // does not work
  }
}

I cannot change the return type of f to C[Any] anymore ("type mismatch").

Upvotes: 1

Views: 224

Answers (2)

Alexey Romanov
Alexey Romanov

Reputation: 170919

You can use type variable patterns to give a name to the type parameter:

f(1) match {
  case c: C[a] => c.print(c.list(0))
}

Upvotes: 0

chengpohi
chengpohi

Reputation: 14227

  def f(i: Int): C[Any] = {
    i match {
      case 1 => new C(Seq(1, 2, 3))
      case _ => new C(Seq("A", "B", "C"))
    }
  }

Try to set the f method return type: C[Any] from C[_], for typeC[_], the compiler will translate C[_] to C<?>.

for:

  def g[P](c: C[P]) = {
    c.print(c.list(0))
  }

this method works, this is caused by that we have bound P type in this method g, so the compiler can infer this generic P (Object type).

but in main method:

c.print(c.list(0))

There is no type context for c, and c's type is C[_], but c.list's type is Seq[Any], and for the Generic Type P in the c.print will be thought as _$1 type. so the type mismatch compile error throwed.

Upvotes: 1

Related Questions