Scala’s	

Types of Types
bg = game @ http://www.swordandsworcery.com/

Konrad 'ktoso' Malawski	

Lambda Days 2014 @ Kraków
_@

Konrad `@ktosopl` Malawski

geecon.org	

Java.pl / KrakowScala.pl	

sckrk.com / meetup.com/Paper-Cup @ London	

GDGKrakow.pl 	

meetup.com/Lambda-Lounge-Krakow
Types
Types

“Implementation is an implementation detail.”	

~ ktoso
Types in Scala
Types in Scala
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!
!

^
Types in Scala
Types are:	

!

static
strong

var two = 2!
two = "two"!
!

error: type mismatch;!
found
: String("two")!
required: Int!
two = "two"!
^
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"
Types in Scala
Types are:	

!
val n: Int = 2

!

static
strong
inferred
annotated after :	


!
!

!
def add(a: Int, b: Int): Int!
Types with Traits
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!
Types with Traits
Traits are:	

!

interfaces
with implementation
!

trait HasName { def name = "name" }!
!

object Human extends HasName!
!

Human.name == "name"!
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?!
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
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!
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
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!
Type Refinement
Type Refinement
trait Human!
trait Robot

val human: Human = new Human {}!
val roman: Human = new Robot!
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!
Compound Types
Compound Types
are	

intersections
of types
!
!
!
!
!

trait
def
}!
trait
def
}!

Openable {!
open()!
Closable {!
close()!
Compound Types
are	

intersections
!

!
!
!
!

open()

trait
def
}!
trait
def
}!

Openable {!
open()!
Closable {!
close()!

close()
Compound Types
are	

intersections
!

trait
def
}!
trait
def
}!

Openable {!
open()!
Closable {!
close()!

!
!
! def openAndClose(it: Openable with Closable) {!
it.open()
!
!

it.close()!
}
Compound Types
are	

intersections
!

trait
def
}!
trait
def
}!

Openable {!
open()!
Closable {!
close()!

!
!
! def openAndClose(it: Openable with Closable) {!
it.open()
!
!

it.close()!
}
Compound Types

this.type

trait
def
}!
trait
def
}!

Openable {!
open(): this.type!
Closable {!
close()!

!
!
!
def openAndClose(it: Openable with Closable) =!
!

it.open().close()
!

Type Parameters
!

Type Parameters	

[Type Variance]
!

Type Parameters	

[Type Variance]	

<: Type Bounds >:
Type Parameters
type constructor

class C[T]
type parameter
Type Variance

class C[T] // in-variant!
class C[+T] // co-variant!
class C[-T] // contra-variant!
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
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)!
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]!
!
!
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]!
!
!
Structural Type
Structural Types

// a type!
class Closeable {!
def close()!
}

=>

// structural type!
type Closeable = {!
def close()!
}
Structural Types
Kinda’ like “duck typing”

def send(msg: String, box: {def receive(a: String)}) =!
box receive msg

structural type
Structural Types
type alias
type MailBoxLike = { !
def receive(a: String)!
}
def send(msg: String, box: MailboxLike) =!
box receive msg
Structural Types

type MailBoxLike = { !
def receive(a: String)!
}
def send(msg: String, box: MailboxLike) =!
box receive msg
object Home { def receive(a: String) = ??? }!
object Work { def receive(a: String) = ??? }
send("hello at home", Home)!
send("hello at work", Work)
Type Member
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
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!!
}
Type Alias
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)!
}!
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)!
}!
Type Alias
From Type Parameter to Type Members

trait Builder[From, To]

=>

trait Builder {!
type From!
type To!
def make(in: From): To!
}
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)!
}!
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)!
}!
Phantom Types
Phantom Types

Phantom Types are never actually instanciated.

Exactly!

uhm… where are they?
Phantom Types
Marker traits:
sealed trait DoorState!
final class Open
extends DoorState!
final class Closed extends DoorState!
Phantom Types
Marker traits:
sealed trait DoorState!
final class Open
extends DoorState!
final class Closed extends DoorState!

trait Door[State <: DoorState] {!
!

def open[T >: State <: Closed](): Door[Open] !
!
!

def close[T >: State <: Open](): Door[Closed]!
!

}!
!
Phantom Types
Only slide in this talk with implementation!

class Door[State <: DoorState] private () {!
!

def open[T >: State <: Closed]() = !
this.asInstanceOf[Door[Open]]!
!

def close[T >: State <: Open]() =
this.asInstanceOf[Door[Closed]]!

!

}!
!

object Door { def apply() = new Door[Closed] }
Phantom Types
Marker traits:
sealed trait DoorState!
final class Open
extends DoorState!
final class Closed extends DoorState!

class Door[State <: DoorState] private () {!
!

def open[T >: State <: Closed]() = !
this.asInstanceOf[Door[Open]]!
!

def stop[T >: State <: Open]() =
!
this.asInstanceOf[Door[Closed]]!
}!
!

object Door { def apply() = new Door[Closed] }
Phantom Types
Marker traits:
sealed trait DoorState!
final class Open
extends DoorState!
final class Closed extends DoorState!

class Door[State <: DoorState] private () {!
!

def open[T >: State <: Closed]() = !
this.asInstanceOf[Door[Open]]!
!

def stop[T >: State <: Open]() =
!
this.asInstanceOf[Door[Closed]]!
}!
!

object Door { def apply() = new Door[Closed] }
Phantom Types
Marker traits:
sealed trait DoorState!
final class Open
extends DoorState!
final class Closed extends DoorState!

class Door[State <: DoorState] private () {!
!

def open[T >: State <: Closed]() = !
this.asInstanceOf[Door[Open]]!
!

def stop[T >: State <: Open]() =
!
this.asInstanceOf[Door[Closed]]!
}!
!

object Door { def apply() = new Door[Closed] }
Phantom Types
Marker traits:
sealed trait DoorState!
final class Open
extends DoorState!
final class Closed extends DoorState!

class Door[State <: DoorState] private () {!
!

def open[T >: State <: Closed]() = !
this.asInstanceOf[Door[Open]]!
!

def stop[T >: State <: Open]() =
!
this.asInstanceOf[Door[Closed]]!
}!
!

object Door { def apply() = new Door[Closed] }
Phantom Types
val closed = Door()!
// closed: Door[Closed]
Phantom Types
val closed = Door()!
// closed: Door[Closed]!
!

val opened = closed.open()!
// opened: Door[Open]
Phantom Types
val closed = Door()!
// closed: Door[Closed]!
!

val opened = closed.open()!
// opened: Door[Open]!
!

val closedAgain = opened.close()!
// closedAgain: Door[Closed]!
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]
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]
Higher Kinded Types
Kind:

x
Proper Kind
Int!

scala> :kind -v 42!
!

scala.Int's kind is A!
*!
!

This is a proper type.
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.
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
Higher Kinded Types

import scala.language.higherKinds!
!

takes Type Constructor

trait Functor [F[_]] {!
def map[A,B] (fn: A => B)(fa: F[A]): F[B]!
}
Higher Kinded Types
import scala.language.higherKinds!
!

trait Functor [F[_]] {!
def map[A,B] (fn: A => B)(fa: F[A]): F[B]!
}

trait Functor [List] {!
def map[Int,String] (fn: Int => String)!
(fa: List[Int]): List[String]!
}
Higher Kinded Types
import scala.language.higherKinds!
!

trait Functor [F[_]] {!
def map[A,B] (fn: A => B)(fa: F[A]): F[B]!
}

val funct = new Functor[List] {!
def map[String, Int] !
(f: String => Int)!
(fa: List[String])!
: List[Int] = fa map f // cheating ;-)!
}
Higher Kinded Types
import scala.language.higherKinds!
!

trait Functor [F[_]] {!
def map[A,B] (fn: A => B)(fa: F[A]): F[B]!
}
val funct = new Functor[List] {!
def map[String, Int] !
(f: String => Int)!
(fa: List[String]): List[Int] = !
! ! !!!
fa map f // cheating ;-)!
}
val f: Int => String = _.toString!
funct.map(f)(List(1, 2)) == List("1", "2")!
Power up: Ad-Hoc Polymorphism
trait Container[M[_]] { !
def put[A](x: A): M[A]; def get[A](m: M[A]): A !
}!
implicit val listContainer = new Container[List] { !
def put[A](x: A) = List(x)!
def get[A](m: List[A]) = m.head !
}!
!

implicit val optionContainer = new Container[Some] {!
def put[A](x: A) = Some(x);!
def get[A](m: Some[A]) = m.get !
}!
Power up: Ad-Hoc Polymorphism
trait Container[M[_]] { !
def put[A](x: A): M[A]; def get[A](m: M[A]): A !
}!

def tupleize[M[_]: Container, A, B]!
(fst: M[A], snd: M[B]) !
(implicit c: Container[M]): M[(A, B)] =
c.put(c.get(fst), c.get(snd))
tupleize(Some(1), Some(2))!
Some((1,2)): Some[(Int, Int)]!
!

tupleize(List(1), List(“2”))!
List((1,2)): List[(Int, String)]!
Power up: Ad-Hoc Polymorphism
trait Container[M[_]] { !
def put[A](x: A): M[A]; def get[A](m: M[A]): A !
}!

def tupleize[M[_]: Container, A, B]!
(fst: M[A], snd: M[B]) !
(implicit c: Container[M]): M[(A, B)] =
c.put(c.get(fst), c.get(snd))
tupleize(Some(1), Some(2))!
Some((1,2)): Some[(Int, Int)]!
!

tupleize(List(1), List(“2”))!
List((1,2)): List[(Int, String)]!
Type Class
Type Class	

A.K.A. “ad-hoc polymorphism”
Type Class	

A.K.A. “More pattern, than type”
Type Class	

A.K.A. “Stay in this room”
Type Class	

A.K.A. “Stay in this room”	

Jerzy has an entire talk about them
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)!
}!
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]
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]
Type Class
implicit val jsonNum = Writes[Num, Json] {
def (n1: Num, n2: Num) = n1.a < n1.!
}!
!

case class Num(a: Int) extends Writeable[Num]
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]()!
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)!
Links & Kudos
ktoso/scala-types-of-types @ github

12444 words and growing
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
Links and Kudos
http://docs.scala-lang.org/
!
http://ktoso.github.io/scala-types-of-types/	

!
!
http://blog.echo.sh/post/68636331334/experimenting-with-peano-numbers-on-scalas-type-system-1	

!
http://stackoverflow.com/questions/6246719/what-is-a-higher-kinded-type-in-scala	

!
http://twitter.github.io/scala_school/advanced-types.html	

!
https://github.com/earldouglas/scala-scratchpad/tree/master/type-lambdas	

!
http://www.scala-lang.org/old/node/136	

!
http://eed3si9n.com/learning-scalaz/polymorphism.html	

!
!
!
Dziękuję!
Thank you!
あろがとう!

(guess “type” occurrences)

K.Malawski @ ebay.com
Konrad.Malwski @ geecon.org
t: ktosopl / g: ktoso
blog: project13.pl

Lambda Days 2014 @ Kraków

Scala Types of Types @ Lambda Days

  • 1.
    Scala’s Types of Types bg= game @ http://www.swordandsworcery.com/ Konrad 'ktoso' Malawski Lambda Days 2014 @ Kraków
  • 2.
    _@ Konrad `@ktosopl` Malawski geecon.org Java.pl/ KrakowScala.pl sckrk.com / meetup.com/Paper-Cup @ London GDGKrakow.pl meetup.com/Lambda-Lounge-Krakow
  • 3.
  • 4.
    Types “Implementation is animplementation detail.” ~ ktoso
  • 5.
  • 6.
  • 7.
    Types in Scala Typesare: ! 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 Typesare: ! static strong var two = 2! two = "two"! ! error: type mismatch;! found : String("two")! required: Int! two = "two"! ^
  • 9.
    Types in Scala Typesare: ! 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 Typesare: ! val n: Int = 2 ! static strong inferred annotated after : ! ! ! def add(a: Int, b: Int): Int!
  • 11.
  • 12.
    Types with Traits Traitsare: ! interfaces ! implementation: trait HasName { ! def name: String! }! ! ! class Human extends HasName {! def name = ""! } class Human(val name: String) ! extends HasName!
  • 13.
    Types with Traits Traitsare: ! interfaces with implementation ! trait HasName { def name = "name" }! ! object Human extends HasName! ! Human.name == "name"!
  • 14.
    Types with Traits Traitsare: ! 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 Robotextends 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 Robotextends 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 traitRobot 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 Robotextends 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!
  • 19.
  • 20.
    Type Refinement trait Human! traitRobot val human: Human = new Human {}! val roman: Human = new Robot!
  • 21.
    Type Refinement trait Human! traitRobot 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!
  • 22.
  • 23.
  • 24.
  • 25.
    Compound Types are intersections ! trait def }! trait def }! Openable {! open()! Closable{! close()! ! ! ! def openAndClose(it: Openable with Closable) {! it.open() ! ! it.close()! }
  • 26.
    Compound Types are intersections ! trait def }! trait def }! Openable {! open()! Closable{! close()! ! ! ! def openAndClose(it: Openable with Closable) {! it.open() ! ! it.close()! }
  • 27.
    Compound Types this.type trait def }! trait def }! Openable {! open():this.type! Closable {! close()! ! ! ! def openAndClose(it: Openable with Closable) =! ! it.open().close()
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
    Type Variance class C[T]// in-variant! class C[+T] // co-variant! class C[-T] // contra-variant!
  • 33.
    Type Bounds (stillvariance) 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]! ! !
  • 37.
  • 38.
    Structural Types // atype! class Closeable {! def close()! } => // structural type! type Closeable = {! def close()! }
  • 39.
    Structural Types Kinda’ like“duck typing” def send(msg: String, box: {def receive(a: String)}) =! box receive msg structural type
  • 40.
    Structural Types type alias typeMailBoxLike = { ! def receive(a: String)! } def send(msg: String, box: MailboxLike) =! box receive msg
  • 41.
    Structural Types type MailBoxLike= { ! def receive(a: String)! } def send(msg: String, box: MailboxLike) =! box receive msg object Home { def receive(a: String) = ??? }! object Work { def receive(a: String) = ??? } send("hello at home", Home)! send("hello at work", Work)
  • 42.
  • 43.
    Type Member Same goalas 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!! }
  • 45.
  • 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 TypeParameter 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)! }!
  • 51.
  • 52.
    Phantom Types Phantom Typesare never actually instanciated. Exactly! uhm… where are they?
  • 53.
    Phantom Types Marker traits: sealedtrait DoorState! final class Open extends DoorState! final class Closed extends DoorState!
  • 54.
    Phantom Types Marker traits: sealedtrait DoorState! final class Open extends DoorState! final class Closed extends DoorState! trait Door[State <: DoorState] {! ! def open[T >: State <: Closed](): Door[Open] ! ! ! def close[T >: State <: Open](): Door[Closed]! ! }! !
  • 55.
    Phantom Types Only slidein this talk with implementation! class Door[State <: DoorState] private () {! ! def open[T >: State <: Closed]() = ! this.asInstanceOf[Door[Open]]! ! def close[T >: State <: Open]() = this.asInstanceOf[Door[Closed]]! ! }! ! object Door { def apply() = new Door[Closed] }
  • 56.
    Phantom Types Marker traits: sealedtrait DoorState! final class Open extends DoorState! final class Closed extends DoorState! class Door[State <: DoorState] private () {! ! def open[T >: State <: Closed]() = ! this.asInstanceOf[Door[Open]]! ! def stop[T >: State <: Open]() = ! this.asInstanceOf[Door[Closed]]! }! ! object Door { def apply() = new Door[Closed] }
  • 57.
    Phantom Types Marker traits: sealedtrait DoorState! final class Open extends DoorState! final class Closed extends DoorState! class Door[State <: DoorState] private () {! ! def open[T >: State <: Closed]() = ! this.asInstanceOf[Door[Open]]! ! def stop[T >: State <: Open]() = ! this.asInstanceOf[Door[Closed]]! }! ! object Door { def apply() = new Door[Closed] }
  • 58.
    Phantom Types Marker traits: sealedtrait DoorState! final class Open extends DoorState! final class Closed extends DoorState! class Door[State <: DoorState] private () {! ! def open[T >: State <: Closed]() = ! this.asInstanceOf[Door[Open]]! ! def stop[T >: State <: Open]() = ! this.asInstanceOf[Door[Closed]]! }! ! object Door { def apply() = new Door[Closed] }
  • 59.
    Phantom Types Marker traits: sealedtrait DoorState! final class Open extends DoorState! final class Closed extends DoorState! class Door[State <: DoorState] private () {! ! def open[T >: State <: Closed]() = ! this.asInstanceOf[Door[Open]]! ! def stop[T >: State <: Open]() = ! this.asInstanceOf[Door[Closed]]! }! ! object Door { def apply() = new Door[Closed] }
  • 60.
    Phantom Types val closed= Door()! // closed: Door[Closed]
  • 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]
  • 65.
  • 66.
    Kind: x Proper Kind Int! scala> :kind-v 42! ! scala.Int's kind is A! *! ! This is a proper type.
  • 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
  • 69.
    Higher Kinded Types importscala.language.higherKinds! ! takes Type Constructor trait Functor [F[_]] {! def map[A,B] (fn: A => B)(fa: F[A]): F[B]! }
  • 70.
    Higher Kinded Types importscala.language.higherKinds! ! trait Functor [F[_]] {! def map[A,B] (fn: A => B)(fa: F[A]): F[B]! } trait Functor [List] {! def map[Int,String] (fn: Int => String)! (fa: List[Int]): List[String]! }
  • 71.
    Higher Kinded Types importscala.language.higherKinds! ! trait Functor [F[_]] {! def map[A,B] (fn: A => B)(fa: F[A]): F[B]! } val funct = new Functor[List] {! def map[String, Int] ! (f: String => Int)! (fa: List[String])! : List[Int] = fa map f // cheating ;-)! }
  • 72.
    Higher Kinded Types importscala.language.higherKinds! ! trait Functor [F[_]] {! def map[A,B] (fn: A => B)(fa: F[A]): F[B]! } val funct = new Functor[List] {! def map[String, Int] ! (f: String => Int)! (fa: List[String]): List[Int] = ! ! ! !!! fa map f // cheating ;-)! } val f: Int => String = _.toString! funct.map(f)(List(1, 2)) == List("1", "2")!
  • 73.
    Power up: Ad-HocPolymorphism trait Container[M[_]] { ! def put[A](x: A): M[A]; def get[A](m: M[A]): A ! }! implicit val listContainer = new Container[List] { ! def put[A](x: A) = List(x)! def get[A](m: List[A]) = m.head ! }! ! implicit val optionContainer = new Container[Some] {! def put[A](x: A) = Some(x);! def get[A](m: Some[A]) = m.get ! }!
  • 74.
    Power up: Ad-HocPolymorphism trait Container[M[_]] { ! def put[A](x: A): M[A]; def get[A](m: M[A]): A ! }! def tupleize[M[_]: Container, A, B]! (fst: M[A], snd: M[B]) ! (implicit c: Container[M]): M[(A, B)] = c.put(c.get(fst), c.get(snd)) tupleize(Some(1), Some(2))! Some((1,2)): Some[(Int, Int)]! ! tupleize(List(1), List(“2”))! List((1,2)): List[(Int, String)]!
  • 75.
    Power up: Ad-HocPolymorphism trait Container[M[_]] { ! def put[A](x: A): M[A]; def get[A](m: M[A]): A ! }! def tupleize[M[_]: Container, A, B]! (fst: M[A], snd: M[B]) ! (implicit c: Container[M]): M[(A, B)] = c.put(c.get(fst), c.get(snd)) tupleize(Some(1), Some(2))! Some((1,2)): Some[(Int, Int)]! ! tupleize(List(1), List(“2”))! List((1,2)): List[(Int, String)]!
  • 76.
  • 77.
  • 78.
    Type Class A.K.A. “Morepattern, than type”
  • 79.
  • 80.
    Type Class A.K.A. “Stayin this room” Jerzy has an entire talk about them
  • 81.
    Type Class // notype 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 valjsonNum = Writes[Num, Json] { def (n1: Num, n2: Num) = n1.a < n1.! }! ! case class Num(a: Int) extends Writeable[Num]
  • 85.
    Type Class implicit valjsonNum = 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 valjsonNum = 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)!
  • 87.
  • 88.
  • 89.
    Other Types ofTypes 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
  • 90.
  • 91.
    Dziękuję! Thank you! あろがとう! (guess “type”occurrences) K.Malawski @ ebay.com Konrad.Malwski @ geecon.org t: ktosopl / g: ktoso blog: project13.pl Lambda Days 2014 @ Kraków