• Covariance : +
  • Contravariance : -
  • Invariance : default

Covariant

class Getable[+T](val data: T)
val gs = new Getable("MyString")
def get(in:Getable[Any]) { println("It's " + in.data) }
get(gs)


def getNum(in: Getable[Number]) = in.data.intValue
def gd = new Getable(new java.lang.Double(33.3))
getNum(gd)

Contravariant

class Putable[-T] {
  def put(in: T) {println("Putting " + in) }
}

def writeOnly(in: Putable[String]) { in.put("Hello") }
val p = new Putable[AnyRef]
writeOnly(p)

trait DS[-In, +Out] { def apply(i: In) : Out }
val t1 = new DS[Any, Int] { def apply(i:Any) = i.toString.toInt }
def check(in: DS[String, Any]) = in("333")
check(t1)
// res77: Any = 333

Type Bounds

  • Upper Bound : <:
  • Lower Bound : >:
class Food (val name: String)
class Cake (name: String) extends Food(name)
class Toy (name: String)
def foodName[A <: Food](f: A) { println(f.name) }

foodName(new Cake("Coco Cake"))
// Coco Cake
foodName(new Food("some foods"))
// some foods
foodName(new Toy("robot gift"))
// <console>:16: error: inferred type arguments [Toy] do not conform to method foodName's type parameter bounds [A <: Food]
//        foodName(new Toy("robot gift"))

implicit

object Utils {
     |   implicit class Demo(in: String) { def demo01 = in.toList } 
     | }
// defined object Utils
import Utils._
"abcd".demo01
// res97: List[Char] = List(a, b, c, d)

Abstract Type

trait Box {
  type A
  def value: A
}

object BoxInt extends Box {
  type A = Int
  def value = 2
}

trait Box2 {
  type A <: AnyVal
  def value: A
}

object BoxInt2 extends Box2 {
  type A = Int
  def value = 3
}

higher-kinded types

:kind List
:kind -v List