7. Types in Scala
Types are:
!
static
class Robot!
class Human !
!
val human: Human = new Human!
val roman: Human = new Robot!
!
!
error: type mismatch;!
!
found
: Robot!
!
required: Human!
!
val robot: Human = new Robot!
!
^
8. Types in Scala
Types are:
!
static
strong
var two = 2!
two = "two"!
!
error: type mismatch;!
found
: String("two")!
required: Int!
two = "two"!
^
9. Types in Scala
Types are:
!
static
strong
inferred
!
val n = 2!
n.getClass.toString == "int"!
!
!
!class Human!
!val p = new Human!
p.getClass.toString == "class Human"
10. Types in Scala
Types are:
!
val n: Int = 2
!
static
strong
inferred
annotated after :
!
!
!
def add(a: Int, b: Int): Int!
12. Types with Traits
Traits are:
!
interfaces
!
implementation:
trait HasName { !
def name: String!
}!
!
!
class Human extends HasName {!
def name = ""!
}
class Human(val name: String) !
extends HasName!
13. Types with Traits
Traits are:
!
interfaces
with implementation
!
trait HasName { def name = "name" }!
!
object Human extends HasName!
!
Human.name == "name"!
14. Types with Traits
Traits are:
!
interfaces
with implementation
can be “mixed in”
trait Robot!
trait Humanoid!
trait Lasers!
!
object X extends Robot !
with Humanoid!
with Lasers!
!
Multiple inheritance panic?!
15. Type linearization
trait Robot extends Lasers!
trait Humanoid!
trait Lasers
object X extends Robot !
with Humanoid!
with Lasers
// type linearization:!
X Robot Humanoid Lasers
// reverse!
X Lasers Humanoid Robot! !
!
// expand!
X Lasers Humanoid Robot Lasers
// right-keep-unique!
X Lasers Humanoid Robot Lasers!
X
Humanoid Robot Lasers
// add common!
X
Humanoid Robot Lasers Object Any
16. Type linearization
trait Robot extends Lasers!
trait Humanoid!
trait Lasers
object X extends Robot !
with Humanoid!
with Lasers
// don’t trust me, trust the compiler:!
import scala.reflect.runtime.universe._!
typeOf[X.type].baseClasses.map(_.name).mkString(“ extends ")!
!
// output:!
X extends Humanoid !
extends Robot extends Lasers !
extends Object extends Any!
17. Type linearization
reordered slightly
trait Robot extends Lasers!
trait Humanoid!
trait Lasers
object X extends Humanoid!
with Lasers!
with Robot
// type linearization:!
X Humanoid Lasers Robot
// reverse!
X Robot Lasers Humanoid! !
!
// expand!
X Robot Lasers Lasers Humanoid
// right-keep-unique!
X Robot Lasers Lasers Humanoid!
X Robot
Lasers Humanoid
// add common!
X Robot
Lasers Humanoid Object Any
18. Type linearization
trait Robot extends Lasers!
trait Humanoid!
trait Lasers
object X extends Humanoid!
with Lasers!
with Robot
// don’t trust me, trust the compiler:!
import scala.reflect.runtime.universe._!
typeOf[X.type].baseClasses.map(_.name).mkString(“ extends ")!
!
// output:!
X extends Robot !
extends Lasers extends Humanoid!
extends Object extends Any!
21. Type Refinement
trait Human!
trait Robot
val human: Human = new Human {}!
val roman: Human = new Robot with Human!
plain trait composition
type refinement
Waaah!
It’s a robot with human traits!
32. Type Variance
class C[T] // in-variant!
class C[+T] // co-variant!
class C[-T] // contra-variant!
33. Type Bounds (still variance)
class Parent!
class Bottom extends Parent!
!
Type Bounds
!
Parent >: Bottom
Bottom <: Parent
Parent =:= Parent
// parent is “more” general!
// bottom is “less” general!
// parent is “equal” parent
34. Type Variance
class C[T]
// in-variant
val x: C[Parent] = new C[Parent]!
!
val x: C[Parent] = new C[Bottom]!
error: type mismatch; found: C[Bottom] required: C[Parent]!
Note: Bottom <: Parent, but class C is invariant in type A.!
You may wish to define A as +A instead. (SLS 4.5)!
!
val x: C[Bottom] = new C[Parent]!
error: type mismatch; found: C[Parent] required: C[Bottom]!
Note: Parent >: Bottom, but class C is invariant in type A.!
You may wish to define A as -A instead. (SLS 4.5)!
35. Type Variance
class C[+T]
// co-variant
val x: C[Parent] = new C[Parent]!
!
val x: C[Parent] = new C[Bottom]!
!
val x: C[Bottom] = new C[Parent]!
error: type mismatch; found: C[Parent] required: C[Bottom]!
!
!
36. Type Variance
class C[-T]
// contra-variant
val x: C[Parent] = new C[Parent]!
!
val x: C[Parent] = new C[Bottom]!
error: type mismatch; found: C[Bottom] required: C[Parent]!
!
val x: C[Bottom] = new C[Parent]!
!
!
43. Type Member
Same goal as
Type Parameter
if List was using Type Params
trait StringList!
extends List[String]
=>
trait StringList !
extends List {!
type A = String!
}
if List was using Type Members
44. Type Member + Type Bound
Same as + / - variance
trait List {!
type A!
}
=>
trait NumbersList extends List {!
type A <: Number!
}
trait IntegerList extends NumbersList {!
type A = Integer!
}
trait FailList extends NumbersList {!
type A = Human // Human is not <: Number!!
}
46. Without Type Alias
“1st” and “2nd” type param
ALL HOPE IS LOST!
object `bytes -> string` !
extends Builder[Array[Byte], String] {!
!
def make(in: Array[Byte]): String = new String(in)!
}!
47. Without Type Alias
“1st” and “2nd” type param
Some meaning is lost!
object `bytes -> string` !
extends Builder[Array[Byte], String] {!
!
def make(in: Array[Byte]): String = new String(in)!
}!
48. Type Alias
From Type Parameter to Type Members
trait Builder[From, To]
=>
trait Builder {!
type From!
type To!
def make(in: From): To!
}
49. Type Alias
trait Builder { type From; type To; def make(in: From): To }!
trait StringBuilder extends Builder {!
type To = String!
}
trait FromBytesBuilder extends Builder {!
type From = Array[Byte]!
}
object `bytes -> string` extends Builder!
with FromBytesBuilder!
with StringBuilder {!
!
def make(in: From): To = new String(in)!
}!
50. Type Alias
trait Builder { type From; type To; def make(in: From): To }!
object `bytes -> string` extends Builder {!
type From = Array[Bytes]!
type To = String!
!
def make(in: From): To = new String(in)!
}!
61. Phantom Types
val closed = Door()!
// closed: Door[Closed]!
!
val opened = closed.open()!
// opened: Door[Open]
62. Phantom Types
val closed = Door()!
// closed: Door[Closed]!
!
val opened = closed.open()!
// opened: Door[Open]!
!
val closedAgain = opened.close()!
// closedAgain: Door[Closed]!
63. Phantom Types
val closed = Door()!
// closed: Door[Closed]!
!
val opened = closed.open()!
// opened: Door[Open]!
!
val closedAgain = opened.close()!
// closedAgain: Door[Closed]!
!
closed.close()!
error: type arguments [Closed] do not conform to method
close's type parameter bounds [T >: Closed <: Open]
64. Phantom Types
val closed = Door()!
// closed: Door[Closed]!
!
val opened = closed.open()!
// opened: Door[Open]!
!
val closedAgain = opened.close()!
// closedAgain: Door[Closed]!
!
closed.close()!
error: type arguments [Closed] do not conform to method
close's type parameter bounds [T >: Closed <: Open]!
!
opened.open()!
error: type arguments [Open] do not conform to method !
open's type parameter bounds [T >: Open <: Closed]
67. Kind: x -> x
Type Constructor
List[+A]!
scala> :kind -v List!
!
scala.collection.immutable.List's kind is F[+A]!
* -(+)-> *!
!
This is a type constructor: !
a 1st-order-kinded type.
68. Kind:
(x -> x) -> x
Higher Kind
import language.higherKinds!
!
class Functor[M[_]]!
scala> :kind -v Functor[List]!
!
Functor's kind is X[F[A]]!
(* -> *) -> *!
!
This is a type constructor that takes type constructor(s): !
a higher-kinded type
81. Type Class
// no type classes yet!
trait Writeable[Out] {!
def write: Out!
}!
!
case class Num(a: Int, b: Int) extends Writeable[Json] {!
def write = Json.toJson(this)!
}!
82. Type Class
trait Writes[In, Out] {
def write(in: In): Out!
}!
!
!
Separated “what” from “who”
trait Writeable[Self] {
def writeAs[Out]()!
(implicit writes: Writes[Self, Out]): Out =!
! ! ! !
writes write this!
}!
!
!
!
implicit val jsonNum = Writes[Num, Json] {!
! def write(n: Num) = Json.toJson(n)!
!
}!
!
case class Num(a: Int) extends Writeable[Num]
83. Type Class
trait Writes[In, Out] {
def write(in: In): Out!
}!
!
!
trait Writeable[Self] {
def writeAs[Out]()!
(implicit writes: Writes[Self, Out]): Out =!
! ! ! !
writes write this!
}!
Implicit parameter
!
!
!
implicit val jsonNum = Writes[Num, Json] {!
! def write(n: Num) = Json.toJson(n)!
!
}!
!
Implicit value
case class Num(a: Int) extends Writeable[Num]
84. Type Class
implicit val jsonNum = Writes[Num, Json] {
def (n1: Num, n2: Num) = n1.a < n1.!
}!
!
case class Num(a: Int) extends Writeable[Num]
85. Type Class
implicit val jsonNum = Writes[Num, Json] {
def (n1: Num, n2: Num) = n1.a < n1.!
}!
!
case class Num(a: Int) extends Writeable[Num]
you write:
val jsonNum = Num(12).writeAs[Json]()!
86. Type Class
implicit val jsonNum = Writes[Num, Json] {
def (n1: Num, n2: Num) = n1.a < n1.!
}!
!
case class Num(a: Int) extends Writeable[Num]
you write:
val jsonNum = Num(12).writeAs[Json]()!
compiler does:
val jsonNum = Num(12).writeAs[Json]()(jsonNum)!
89. Other Types of Types
type annotation
case class
type projection
unified type system
value class
self recursive type
bottom types
type class
type constructor
type variance
universal trait
specialized type
traits
self type annotation
dynamic type
type refinements
phantom type
existential type
type alias
structural type
type lambda
abstract type member
path dependent type
algebraic data type