Home > database >  Type Arguments and Bounds in Scala
Type Arguments and Bounds in Scala

Time:12-09

I have the following example:

import scala.concurrent.Future

trait MyTrait[F[_]] {

  case class Test[X[_]](x: X[Int])

  def test[G[_]]: F[Test[G]]

}
class LocImpl extends MyTrait[Future] {

  import scala.concurrent.ExecutionContext.Implicits.global

  def test[Option]: Future[Test[Option]] = {
    Future { new Test[Option](Option(1)) }
  }
}

Which fails compilation due to the reason that:

Type argument Option does not have the same kind as its bound [_$2]

I'm binding the generic type on the test function to Option and binding the trait to Future. So what is the problem here?

https://scastie.scala-lang.org/35pqGtqnQIGvZpGl4BTlFg

CodePudding user response:

For the reference, the beginning was here: Scala Higher Kinded Types for Traits and Method Parameters

Option in def func[Option]... is not scala.Option, you're just defining a new type parameter calling it Option, it's the same as def func[A]..., you just called A Option, which shadows scala.Option.

This is a difference def func[A] (definition site) vs. func[A] (call site) i.e. whether A is a new type or known type.

It's better to use scalacOptions = "-Xlint:type-parameter-shadow to avoid shadowing known types.

What causes this type error in a pattern guard for matching list of tuples

Strange Error with String in Scala 2.12.7

Type parameters applied to Scala Function

And since def test[Option]... is the same as def test[A]..., errors are understandable. Test[Option] aka Test[A] doesn't make sense because of a disagreement in kind. Option(1) aka A(1) doesn't make sense either.

So it should be just

def test: Future[Test[Option]] = {
  Future { new Test[Option](Option(1)) }
}

without type parameter. But then you break overriding. You seem to want having G an abstract type (to be implemented in inheritors) rather than method's type parameter (when the method must be defined for arbitrary G)

trait MyTrait[F[_]] {

  case class Test[X[_]](x: X[Int])

  type G[_]

  def test: F[Test[G]]

}
class LocImpl extends MyTrait[Future] {

  import scala.concurrent.ExecutionContext.Implicits.global

  type G[A] = Option[A]

  def test: Future[Test[Option]] = {
    Future { new Test[Option](Option(1)) }
  }
}

https://scastie.scala-lang.org/DmytroMitin/rk82W02DQOiFAJ7mghHcAQ/1

It's similar to having G a type parameter of the type class

trait MyTrait[F[_], G[_]] {

  case class Test[X[_]](x: X[Int])

  def test: F[Test[G]]

}
class LocImpl extends MyTrait[Future, Option] {

  import scala.concurrent.ExecutionContext.Implicits.global

  def test: Future[Test[Option]] = {
    Future { new Test[Option](Option(1)) }
  }
}

https://scastie.scala-lang.org/DmytroMitin/rk82W02DQOiFAJ7mghHcAQ/2

  • Related