Upcoming SlideShare
×

# Demystifying Scala Type System

14,109 views
13,916 views

Published on

Présentation au Paris Scala User Group le 28Nov 2012

Published in: Technology
51 Likes
Statistics
Notes
• Full Name
Comment goes here.

Are you sure you want to Yes No
• Be the first to comment

Views
Total views
14,109
On SlideShare
0
From Embeds
0
Number of Embeds
415
Actions
Shares
0
226
0
Likes
51
Embeds 0
No embeds

No notes for slide

### Demystifying Scala Type System

1. 1. Demystifying Scala Type System David Galichet CTO @ CoachClubjeudi 29 novembre 12
2. 2. Schedule Scala Types 101 Types Variance and Type bounds Abstract Type members Ad-Hoc Polymorphism Existential Types Generalized Type Constraintsjeudi 29 novembre 12
3. 3. 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 Piercejeudi 29 novembre 12
4. 4. What is a type ? A Type deﬁnes 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 deﬁned as Cartesian product Types (like case classes or Tuples) Sum Types (like Either) Types can be Abstract and/or Polymorphjeudi 29 novembre 12
5. 5. 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) functionjeudi 29 novembre 12
6. 6. Why typing ? “Make illegal states unrepresentable“ - Yaron Minsky “Where static typing ﬁts, do it every time because it has just fantastic maintenance beneﬁts.” - Simon Peyton Jones Compiler can use Type informations to optimize compiled codejeudi 29 novembre 12
7. 7. Scala Types 101 Scala is Object Oriented and Functional Scala has a strong and static Type System Types are checked at compile time Types can be inferred by the compiler Functions are Types : A => Bjeudi 29 novembre 12
8. 8. Scala Types 101 Types are used to deﬁne [abstract] classes objects traitsjeudi 29 novembre 12
9. 9. Scala Types 101 Any ⟙ Scala types hierarchy AnyVal AnyRef Enclosed by : Primitive Types All Types wrappers Top type ⟙ (Any) Bottom type ⟘ (Nothing) Nothing ⟘ Java Primitive Types are wrapped under AnyVal (Unit, Long, Double, Boolean ...) Since 2.10, you can deﬁne your own AnyValjeudi 29 novembre 12
10. 10. Scala Types 101 Scala Types can be parameterized List[A] Either[A, B] Functions can also take type parameters def show[A](a:A):String = a.toStringjeudi 29 novembre 12
11. 11. Type Variance and Bounds Type Variance goal is to deﬁne inheritance relation By default, Type Parameters are invariant They can also be deﬁned as co-variant or contra-variantjeudi 29 novembre 12
12. 12. Type Variance and Bounds Co-Variance(M[+T]) B M[B] if A extends B then M[A] extends M[B] A M[A] Contra-Variance (M[-T]) if A extends B then M[B] extends M[A] B M[A] A M[B]jeudi 29 novembre 12
13. 13. Type Variance and Bounds Some examples of Types with varying type parameters List[+A] Writer[-A] Function1[-T, +R]jeudi 29 novembre 12
14. 14. 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
15. 15. Type Variance and Bounds First 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 D Function1[A, D] ⋀ A C Function1[B, C]jeudi 29 novembre 12
16. 16. Type Variance and Bounds This is a Function1 instance ! class Test[+A] { def test(a: A): String = a.toString } Type A should be either Invariant or Contra-Variant but it’s Co-Variantjeudi 29 novembre 12
17. 17. 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 Ajeudi 29 novembre 12
18. 18. Type Variance and Bounds Implementation of a List 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] Inherit from any List[T]jeudi 29 novembre 12
19. 19. 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
20. 20. Type Variance and Bounds Implementation of a Writer - Part1 class B { def toString = "I’m B" } class A extends B { def toString = "I’m A" } Inherit from any List[T] 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)jeudi 29 novembre 12
21. 21. Type Variance and Bounds Implementation of a Writer - Part2 write(new B)(bWriter) res> String = I’m B We need a Writer[A] write(new A)(bWriter) res> String = I’m A B Write[A] Fortunately, Writer[B] extends Writer[A]: A Write[B]jeudi 29 novembre 12
22. 22. Type member Concrete Types can be deﬁned in a class, trait or object type Color = String // type Alias type Valid[X] = Either[Throwable, X] // Valid is parametrized with X We can deﬁne these types with their kind : Color or String has kind * Valid or Option has kind * ➞ * Either has kind * ➞ * ➞ *jeudi 29 novembre 12
23. 23. Abstract Type members We can deﬁne Abstract Type in abstract classes or traits Abstract Types are another way to parameterize Types trait Food class Grass extends Food class Fish extends Food trait Species { type SuitableFood <: Food } trait Animal extends Species class Cow extends Animal { type SuitableFood = Grass }jeudi 29 novembre 12
24. 24. Abstract Type members The parameterized type way : trait Food class Grass extends Food class Fish extends Food trait Species[T <: Food] trait Animal[T <: Food] extends Species[T] class Cow extends Animal[Grass]jeudi 29 novembre 12
25. 25. 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 Typeclasses abs :: (Num a, Ord a) => a -> a abs x = if x < 0 then -x else xjeudi 29 novembre 12
26. 26. 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 parameterjeudi 29 novembre 12
27. 27. Ad-Hoc Polymorphism In Scala, we can achieve Ad-Hoc polymorphism using implicits Scala library deﬁnes 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
28. 28. Ad-Hoc Polymorphism We can deﬁne 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
29. 29. Ad-Hoc Polymorphism We can deﬁne our own instances of typeclasses implicit class Printable[A](a: A) { // since Scala 2.10 def printOut(): Unit = println(a.toString) } scala> "test".printOut testjeudi 29 novembre 12
30. 30. Ad-Hoc Polymorphism A 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
31. 31. Ad-Hoc Polymorphism A more concrete example - Part 2 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") )jeudi 29 novembre 12
32. 32. Ad-Hoc Polymorphism Polymorphic Typeclasses instance deﬁnition 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
33. 33. 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 deﬁned using : M[T] forSome { type T } or M[_]jeudi 29 novembre 12
34. 34. Existential Types We can bound existential types : M[T] forSome { type T <: AnyRef } or M[_ <: AnyRef]jeudi 29 novembre 12
35. 35. Generalized Type Constraints Constrain type using an implicit =:= same type <:< lower type >:> super typejeudi 29 novembre 12
36. 36. Generalized Type Constraints Example : trait Food class Grass extends Food class Fish extends Food trait Animal[SuitableFood <: Food] { def fish(implicit ev: SuitableFood =:= Fish){ println("Im fishing") } } class Cow extends Animal[Grass] class Bear extends Animal[Fish]jeudi 29 novembre 12