Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use `with` for bounding type parameters instead of `<:` or `<:<` in Scala?

Tags:

scala

In another question, I'm advised to use with in a place where one normally uses <: or <:<. So instead of defining functions in either of the following two ways:

scala> def f[A,C <: Seq[A]](xs: C) = 0
f: [A, C <: scala.collection.immutable.Seq[A]](xs: C)Int

scala> f(List(1))
<console>:54: error: inferred type arguments [Nothing,List[Int]] do not conform to method f's type parameter bounds [A,C <: scala.collection.immutable.Seq[A]]
              f(List(1))
              ^

scala> implicit def f[A,C](xs: C)(implicit ev: C <:< Seq[A]) = new { def foo = 0 }
f: [A, C](xs: C)(implicit ev: <:<[C,scala.collection.immutable.Seq[A]])java.lang.Object{def foo: Int}

scala> List(0) foo
<console>:54: error: Cannot prove that List[Int] <:< scala.collection.immutable.Seq[A].
              List(0) foo
                  ^

scala> f(List(0)) foo
res17: Int = 0

One can do:

scala> implicit def f[A,C](xs: C with Seq[A]) = new { def foo = 0 }
f: [A, C](xs: C with scala.collection.immutable.Seq[A])java.lang.Object{def foo: Int}

scala> List(0) foo
res18: Int = 0

My question is: besides the above particular case, when should one use with instead of <: or <:< on the type parameter? Why not always use with instead? I'm looking for a discussion of the nuances among the alternatives here. Thanks.

like image 978
Yang Avatar asked Dec 12 '11 21:12

Yang


1 Answers

The meanings are entirely different. C <: Seq[A] means that C is a subtype of Seq[A], as you know; xs: C with Seq[A] doesn't put any bound on C, but means that xs should be both a C and a Seq[A]. Therefore you should normally use the one you actually mean.

In def f[A,C <: Seq[A]](xs: C) the problem is that Scala's compiler can't infer A because it doesn't appear explicitly in the type of arguments. I don't see any reason in principle it couldn't infer A; it just doesn't currently. Replacing the type with C with Seq[A] means A now appears in the type of xs and allows the compiler to infer A. So if you really mean the bound, but A to be inferred, you actually need to write

implicit def f[A,C <: Seq[A]](xs: C with Seq[A])

instead of your third definition, and this is what the answer to the linked question does.

like image 122
Alexey Romanov Avatar answered Nov 15 '22 03:11

Alexey Romanov