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