4

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
              ^
Yang
  • 16,037
  • 15
  • 100
  • 142

2 Answers2

9

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?

Community
  • 1
  • 1
Adriaan Moors
  • 4,256
  • 1
  • 18
  • 10
  • Thanks, but I actually knew `C[A] <: Seq[A]` works - it just restricts me to unary type constructors. I *want* a `C <: Seq[A]`. Anyway, you answered my question by saying inference doesn't deal well with type parameters referencing each other, so I'll mark it as accepted, but would love more details! – Yang Dec 12 '11 at 14:23
1

I don't really know why this happens, although my hunch is it has to do with the variance of Seq's type parameter. I could get the following to work, though:

implicit def view[A, C[~] <: Seq[~] forSome { type ~ }](xs: C[A]) = 
   new { def bar = 0 } 

Is there a reason why you want C—I mean, do you plan to use C inside the method? Because if not, why not just

implicit def view[A](xs: Seq[A]) = new { def bar = 0 }

?

0__
  • 66,707
  • 21
  • 171
  • 266
  • Yes, otherwise I wouldn't need `xs` at all. This is for a pimp that will need to know `A` and `C`. As for the higher-kinded type solution, see my other comment. – Yang Dec 12 '11 at 14:22