Skip to content

Instantly share code, notes, and snippets.

@retronym
Created November 8, 2009 08:02
Show Gist options
  • Save retronym/229163 to your computer and use it in GitHub Desktop.
Save retronym/229163 to your computer and use it in GitHub Desktop.
Demo of generalised type constraints in Scala 2.8
// scala 2.7 simple type constraint. This can only constrain a type parameter of this function.
// Below, in ListW.sumint28, we can't use this approach because we want to constrain T,
// a type param of the enclosing trait.
def sumint27A[T <: Int](l: List[T]) : Int = l.reduceLeft((a: Int, b: Int) => a + b)
trait IntLike[X] extends (X => Int)
object IntLike {
implicit val intIntLike: IntLike[Int] = new IntLike[Int] { def apply(x: Int) = identity(x) }
}
trait ListW[T] {
val l: List[T]
// T can be constrained within the context of this function by requiring an implicit parameter
// to certify that it is IntLike.
def sumint27B(implicit ev: IntLike[T]) : Int = l.map(ev).reduceLeft(_ + _)
// In scala 2.8, we can require an implicit parameter of type T <:< Int (that is, <:<[T, Int])
// The compiler will provide this if T conforms to Int. The parameter `ev` can be used to
// safely cast a value T to Int.
def sumint28(implicit ev: T <:< Int) : Int = l.map(ev).reduceLeft(_ + _)
}
implicit def ListW[T](list: List[T]): ListW[T] = new ListW[T] {
val l = list
}
val intList = List(1, 2, 3)
val stringList = List("1", "2", "3")
sumint27A(intList)
{
import IntLike._
intList.sumint27B
}
intList.sumint28
/* Compiler errors:
sumint27A(stringList) // type arguments [java.lang.String] do not conform to method sumint27's type parameter bounds [T <: Int]
stringList.sumint27 // compile error: could not find implicit value for parameter ev: IntLike[Any]
stringList.sumint28 // compile error: could not find implicit value for parameter ev: <:<[java.lang.String,Int]
*/
@pelotom
Copy link

pelotom commented Aug 6, 2010

Just out of curiosity, when would you use this sort of subclassing constraint rather than a type class?

@retronym
Copy link
Author

retronym commented Aug 6, 2010

It comes in handy when pimping generic types, e.g:

class Tuple2W[A, B](t2: (A, B)) {
    def toSeq[C](implicit ac: A <:< C, bc: B <:

Here we aren't relying on any properties of the types, just finding the Least Upper Bound C.

This can also be used at times when a methods with a regular type bound fails type inference. No hard and fast rules, just can try it as a method of last resort if inference isn't playing nicely.

def foo[X, Y <: FooX = ...
def foo[X, Y <: Foo[X](implicit yfx: Y <:< Foo[X]) = ...

e.g. http://gist.github.com/445874

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment