public
Created — forked from retronym/type-bounds.scala

Tour of Scala Type Bounds

  • Download Gist
type-bounds.scala
Scala
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
class A
class A2 extends A
class B
 
trait M[X]
 
//
// Upper Type Bound
//
def upperTypeBound[AA <: A](x: AA): A = x
 
// equivalently, require a implicit parameter of <:<[AA, A].
// This technique must be used if A is an abstract type from the
// enclosing scope.
def upperTypeBound2[AA](x: AA)(implicit ev: AA <:< A): A = x // compiles to ev(x)
 
 
//
// Lower Type Bound
//
def lowerTypeBound[AA >: A](x: AA, pred: (AA => Boolean)): Boolean = pred(x)
 
// equivalently, require a implicit parameter of <:<[A, AA].
// This technique must be used if A is an abstract type from the
// enclosing scope.
def lowerTypeBound2[AA >: A](x: AA, pred: (AA => Boolean))(implicit ev: A <:< AA): Boolean = pred(x)
 
 
//
// View Bound
//
def viewBound[AA <% A](x: AA): A = x
 
//compiles to:
def viewBound$[AA](x: AA)(implicit ev1$ : AA => A) = ev1$(x)
 
 
//
// Context Bound
//
def contextBound[X: M](x: X) = x;
 
//compiles to:
def contextBound$[X](x: X)(implicit ev1$ : M[X]) = x
 
// In combination:
 
def combo[AA <: A >: B <% String <% Int : M : Ordering] = 0
 
// compiles to:
def combo[AA >: B <: A](implicit
evidence$1: (AA) => String,
evidence$2: (AA) => Int,
evidence$3: M[AA],
evidence$4: Ordering[AA]
): Int = 0
 
//
// Usage
//
{
{
 
upperTypeBound(new A)
upperTypeBound(new A2)
}
 
{
val predA = (a: A) => true
val predAny = (a: Any) => true
lowerTypeBound(new A, predA)
lowerTypeBound(new {}, predAny)
}
 
{
implicit def String2A(s: String): A = new A
viewBound("")
}
{
implicit def MofA: M[A] = new M[A] {}
contextBound(new A)
}
}
 
 
implicit def int2str(i: Int): String = i.toString
def f1[T <% String](t: T) = 0
f1(1)
 
// This could also be expressed with a Context Bound,
// with the help of a type alias representing functions
// from type `F` to type `T`.
trait To[T] { type From[F] = F => T }
def f2[T : To[String]#From](t: T) = 0
f2(1)
 
// A context bound must be used with a type constructor of kind `* => *`.
// However the type constructor `Function1` is of kind `(*, *) => *`.
// The use of the type alias partially applies second type parameter
// with the type `String`, yielding a type constructor of the correct kind
// for use as a context bound.
 
// There is a proposal to allow you to directly express partially applied types
// in Scala, without the use of the type alias inside a trait. You could then write:
//
// def f3[T : [X](X => String)](t: T) = 0

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.