Deferring type inference using generalized type constraints is all about going around limitations with type inference. These limitations are not necessarily bugs, they can be by design.
I can think of two common situations where they are useful:
You want to get the type inside another higher-kinded type, but you have no constraint to get it.
Example:
def sort[T, Coll <: SeqLike[T, Coll](a: Coll): Coll
The compiler has no way to get the type parameter T
because it is not constraint in any way: it does not appear on the left-hand side of a <:
or >:
in the type parameter list, and does not appear in the argument's types.
Generalized type constraints allow here to constraint (through an argument) the type T
:
def sort[T, Coll](a: Coll)(implicit ev: Coll <:< SeqLike[T, Coll]): Coll
Note: this is only one way to do this. There is usually a way to get the same thing something very close without the implicit evidence. Here it would be:
def sort[T, Coll <: SeqLike[T, Coll]](a: Coll with SeqLike[T, Coll]): Coll
You have no control over the type parameter, because it comes from the enclosing class.
For example, adding a flatten
method on List[A]
that only works if A
is a collection itself. You cannot change the type parameter A
just for that one method, but you can locally add a constraint with an implicit ev: A <:< Traversable[B]
or something similar.
Note 2: this isn't what is done in the collection library, which uses implicit ev: (A) => Traversable[B]
, so that anything that can be converted to a collection works (like String
or Array
), but sometimes you do not want that.
Edit to address the sort1
vs sort2
question: adding a generalized type constraint when none is needed can create this kind of error because types become under-constrained. Since there is no constraint on O
in sort1
, ord: O
can be anything. The implicit evidence can only be used to view an O
as an Ordering[T]
within the body of the method.
If you really wanted to keep the implicit evidence, you would have to re-introduce some constraint somewhere. On the type parameter like in sort2
, or on ord
itself:
def sort3[T, O](from: T, to: T)
(implicit ev: O <:< Ordering[T], ord: O with Ordering[T]):Foo[T,O]
in this case, sort2
seems to be the best way to do this.