Demystifying Scala Type System
-
Upload
david-galichet -
Category
Technology
-
view
8.654 -
download
2
description
Transcript of Demystifying Scala Type System
David GalichetCTO @ CoachClub
Demystifying Scala Type System
jeudi 29 novembre 12
Schedule
Scala Types 101
Types Variance and Type bounds
Abstract Type members
Ad-Hoc Polymorphism
Existential Types
Generalized Type Constraints
jeudi 29 novembre 12
What is a type system ?
“A type system is a tractable syntactic method for proving the absence of certain program behaviors by classifying phrases according to the kinds of values they compute.“ – Benjamin Pierce
jeudi 29 novembre 12
What is a type ?
A Type defines a set of values a variable can posses and a set of functions that can be applied to these values
Set of values can be defined as
Cartesian product Types (like case classes or Tuples)
Sum Types (like Either)
Types can be Abstract and/or Polymorph
jeudi 29 novembre 12
What is a type ?
In Functional Languages like Scala, a Function is also a Type that can be assigned to a variable or (higher order) function or returned by a (higher order) function
jeudi 29 novembre 12
Why typing ?“Make illegal states unrepresentable“ - Yaron Minsky
“Where static typing fits, do it every time because it has just fantastic maintenance benefits.” - Simon Peyton Jones
Compiler can use Type informations to optimize compiled code
jeudi 29 novembre 12
Scala Types 101
Scala is Object Oriented and Functional
Scala has a strong and static Type SystemTypes are checked at compile time
Types can be inferred by the compiler
Functions are Types : A => B
jeudi 29 novembre 12
Scala Types 101
Types are used to define
[abstract] classes
objects
traits
jeudi 29 novembre 12
Scala Types 101Scala types hierarchy
Enclosed by : Top type ⟙ (Any)
Bottom type ⟘ (Nothing)
Java Primitive Types are wrapped under AnyVal (Unit, Long, Double, Boolean ...)
Since 2.10, you can define your own AnyVal
Any⟙
AnyRefAnyVal
Primitive Types wrappers All Types
Nothing ⟘
jeudi 29 novembre 12
Scala Types 101
Scala Types can be parameterizedList[A]
Either[A, B]
Functions can also take type parameters
def show[A](a:A):String = a.toString
jeudi 29 novembre 12
Type Variance and Bounds
Type Variance goal is to define inheritance relation
By default, Type Parameters are invariant
They can also be defined as co-variant or contra-variant
jeudi 29 novembre 12
Type Variance and Bounds
Co-Variance(M[+T])
if A extends B then M[A] extends M[B]
Contra-Variance (M[-T])
if A extends B then M[B] extends M[A]
B
A
⇒M[B]
M[A]
B
A
⇒M[A]
M[B]
jeudi 29 novembre 12
Type Variance and Bounds
Some examples of Types with varying type parametersList[+A]
Writer[-A]
Function1[-T, +R]
jeudi 29 novembre 12
Type Variance and Bounds
scala> class Test[+A] { | def test(a: A): String = a.toString | }<console>:8: error: covariant type A occurs in contravariant position in type A of value a
WTF ?
jeudi 29 novembre 12
Type Variance and BoundsFirst of all, take a look at Functions :
Function1[-T,+R]
Functions are Co-Variant on return type (+R) and Contra-Variant on parameters (-T) !
We can substitute Function1[A,D] by Function1[B,C] : B Function1[A, D]
C
D
A Function1[B, C]
⋀ ⇒
jeudi 29 novembre 12
Type Variance and Bounds
Type A should be either Invariant or Contra-Variant but it’s Co-Variant
class Test[+A] { def test(a: A): String = a.toString}
This is a Function1 instance !
jeudi 29 novembre 12
Type Variance and Bounds
Solution : introduce a bounded Type
class Test[+A] { def test[B >: A](b: B): String = b.toString}
Lower Type Bound : this new Type B is a super Type of A
Method test will accept A or any super Type of A
jeudi 29 novembre 12
Type Variance and BoundsImplementation of a List
Inherit from any List[T]
trait List[+T] { def ::[U >: T](u: U): List[U] = Cons(u, this)}case class Cons[T](head: T, tail: List[T]) extends List[T]
case object Nil extends List[Nothing]
jeudi 29 novembre 12
Type Variance and Bounds
Variance is not applicable to mutable state :
trait Mutable[+T] { var t: T // generate a setter:
// def t_=(t: T) {this.t = t}}
Co-Variant parameter in Contra-Variant position
⇒ A mutable List can’t be Co-Variant !
jeudi 29 novembre 12
Type Variance and BoundsImplementation of a Writer - Part1
class B { def toString = "I’m B" }class A extends B { def toString = "I’m A" }
trait Writer[-T] { def write(t: T): String }
val bWriter = new Writer[B] { def write(b: B): String = b.toString }
def write[T](t: T)(w: Writer[T]) = w.write(t)
Inherit from any List[T]
jeudi 29 novembre 12
Type Variance and BoundsImplementation of a Writer - Part2
B Write[A]
A Write[B]
⇒
write(new B)(bWriter)res> String = I’m B
write(new A)(bWriter)res> String = I’m A
We need a Writer[A]
Fortunately, Writer[B] extends Writer[A]:
jeudi 29 novembre 12
Type memberConcrete Types can be defined in a class, trait or object
type Color = String // type Aliastype Valid[X] = Either[Throwable, X] // Valid is parametrized with X
We can define these types with their kind :
Color or String has kind *
Valid or Option has kind * ➞ *
Either has kind * ➞ * ➞ *
jeudi 29 novembre 12
Abstract Type membersWe can define Abstract Type in abstract classes or traits
Abstract Types are another way to parameterize Typestrait Foodclass Grass extends Foodclass Fish extends Food
trait Species { type SuitableFood <: Food}
trait Animal extends Species
class Cow extends Animal { type SuitableFood = Grass}
jeudi 29 novembre 12
Abstract Type membersThe parameterized type way :
trait Foodclass Grass extends Foodclass Fish extends Food
trait Species[T <: Food]trait Animal[T <: Food] extends Species[T]
class Cow extends Animal[Grass]
jeudi 29 novembre 12
Ad-Hoc Polymorphism
Ad-Hoc polymorphism is a way to add behavior to an existing class without modifying it
In Haskell, polymorphism is achieved using typeclasses
abs :: (Num a, Ord a) => a -> aabs x = if x < 0 then -x else x
Typeclasses
jeudi 29 novembre 12
Ad-Hoc Polymorphism
In Scala, we can achieve Ad-Hoc polymorphism using implicits
implicits are used in two places
implicit conversion to convert a type to another
implicit parameter
jeudi 29 novembre 12
Ad-Hoc PolymorphismIn Scala, we can achieve Ad-Hoc polymorphism using implicits
Scala library defines many Typeclasses to achieve Ad-Hoc polymorphism : Integral, Numeric, Ordering ...
def abs[T](x: T)(implicit num: Numeric[T]): T = if(num.lt(x, num.zero)) num.negate(x) else x
def max[T: Ordering](x: T, y: T): T = implicitly[Ordering[T]].max(x, y)
jeudi 29 novembre 12
Ad-Hoc PolymorphismWe can define our own instances of existing typeclasses
case class Student(name: String, score: Float)
implicit object StudentOrdering extends Ordering[Student] { def compare(x: Student, y: Student) = x.score.compareTo(y.score)}
scala> max(Student("Bob", 5.6F), Student("Alice", 5.8F))res0: Student = Student(Alice,5.8)
jeudi 29 novembre 12
Ad-Hoc PolymorphismWe can define our own instances of typeclasses
implicit class Printable[A](a: A) { // since Scala 2.10 def printOut(): Unit = println(a.toString)}
scala> "test".printOuttest
jeudi 29 novembre 12
Ad-Hoc PolymorphismA more concrete example - Part 1
trait Searchable[T] { val id: String val indexedContent: String }
class SearchEngine[T](defaultBuilder: String => T){ def index(searchable: Searchable[T]) { /* ... */ } def search(query: String)(builder: String => T = defaultBuilder): T = builder("0")}
jeudi 29 novembre 12
Ad-Hoc Polymorphism
case class Person(id: Long, name: String)
implicit def person2Searchable(p: Person) = new Searchable[Person] { val id = p.id.toString val indexedContent = p.name }
val fakeEngine = new SearchEngine[Person]( id => Person(id.toLong, "retrieved content") )
A more concrete example - Part 2
jeudi 29 novembre 12
Ad-Hoc PolymorphismPolymorphic Typeclasses instance definition
class Hour[X] private (val x: X) { /* ... */ }
object Hour { def apply[X](x: X)(implicit int: Integral[X]):Hour[X]= new Hour(int.rem(int.plus(int.rem(x, int.fromInt(12)), int.fromInt(12)), int.fromInt(12)))}
implicit def hour2Monoid[X](implicit int: Integral[X]): Monoid[Hour[X]] = new Monoid[Hour[X]] { def append(f1: Hour[X], f2: => Hour[X]) = Hour(int.rem(int.plus(f1.x, f2.x), int.fromInt(12))) def zero = Hour(int.zero)}
jeudi 29 novembre 12
Existential Types
Existential types are reference to type parameter that is unknown
The Scala existential type in M[_] is the dual of Java wildcard M<?>
They can be defined using : M[T] forSome { type T }
or M[_]
jeudi 29 novembre 12
Existential Types
We can bound existential types :M[T] forSome { type T <: AnyRef }
or M[_ <: AnyRef]
jeudi 29 novembre 12
Generalized Type ConstraintsConstrain type using an implicit
=:= same type
<:< lower type
>:> super type
jeudi 29 novembre 12
Generalized Type Constraints
trait Foodclass Grass extends Foodclass Fish extends Food
trait Animal[SuitableFood <: Food] { def fish(implicit ev: SuitableFood =:= Fish){ println("I'm fishing") }}
class Cow extends Animal[Grass]class Bear extends Animal[Fish]
Example :
jeudi 29 novembre 12