Below, the first case succeeds and the second fails. Why do I need an explicit evidence type / why does this Scala type bound fail? What's the type inferencer's particular limitation here in solving for A
?
scala> implicit def view[A, C](xs: C)(implicit ev: C <:< Iterable[A]) = new { def bar = 0 }
view: [A, C](xs: C)(implicit ev: <:<[C,scala.collection.immutable.Iterable[A]])java.lang.Object{def bar: Int}
scala> view(List(1)) bar
res37: Int = 0
scala> implicit def view[A, C <: Seq[A]](xs: C) = new { def bar = 0 }
view: [A, C <: scala.collection.immutable.Seq[A]](xs: C)java.lang.Object{def bar: Int}
scala> view(List(1)) bar
<console>:149: error: inferred type arguments [Nothing,List[Int]] do not conform to method view's type parameter bounds [A,C <: scala.collection.immutable.Seq[A]]
view(List(1)) bar
^
Type inference unfortunately does not deal well with type parameters (such as C) that are bounded by (types that contain) other type parameters in the same type parameter list (here, A).
The version that encodes the constraint using an implicit argument does not suffer from this restriction since constraints imposed by implicits are solved separately from constraints imposed by type parameter bounds.
You can also avoid the cycle by splitting up the type of xs into the type constructor that abstracts over the collection (CC) and the (proper) type (A) that abstracts over its elements, like so:
scala> implicit def view[A, CC[x] <: Seq[x]](xs: CC[A]) = new { def bar = 0 }
view: [A, CC[x] <: Seq[x]](xs: CC[A])Object{def bar: Int}
scala> view(List(1)) bar
res0: Int = 0
For more details on types like CC, please see What is a higher kinded type in Scala?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With