|
| 1 | +###Polymorphism |
| 2 | + |
| 3 | +As a motivating example, let's look at a datastructure that's been fundamental in many functional languages from the beginnings - the Cons-List |
| 4 | + |
| 5 | +It is an immutable linked list, constructed from two building blocks: |
| 6 | + |
| 7 | +* the empty list, which we call `Nil` |
| 8 | +* a cell containg an element and a pointer to the remainder of the list, called `Cons` |
| 9 | + |
| 10 | +Here's what `List(1,2,3)` would look like: |
| 11 | + |
| 12 | + |
| 13 | +We'd have a reference to a `Cons` cell that contains the 1, and a reference to a `Cons` cell that contains 2, which has a reference to a `Cons` cell that contains 3, which has a reference to `Nil` |
| 14 | + |
| 15 | +A nested list like `List(List(true, false), List(3))` would look like: |
| 16 | + |
| 17 | + |
| 18 | +###Cons-Lists in scala |
| 19 | +How would we write this as a class hierarchy in scala? |
| 20 | + |
| 21 | +Here's an outline that would represent lists of integers in this fashion: |
| 22 | + |
| 23 | +```scala |
| 24 | +trait IntList ... |
| 25 | +class Cons(val head: Int, val tail: IntList) extends IntList ... |
| 26 | +class Nil extends IntList ... |
| 27 | +``` |
| 28 | + |
| 29 | +Notice there's a bit of new syntax in the `Cons` declaration - `val head: Int` defines a parameter and a field definition in the class itself. It's equivalent to: |
| 30 | + |
| 31 | +```scala |
| 32 | +class Cons(_head: Int, _tail:IntList) extends IntList { |
| 33 | + val head = _head |
| 34 | + val tail = _tail |
| 35 | +} |
| 36 | +``` |
| 37 | + |
| 38 | +A list is either |
| 39 | + |
| 40 | +* an empty list `new Nil`, or |
| 41 | +* a list `Cons(x, xs) consisting of a `head` element x and a `tail` list xs |
| 42 | + |
| 43 | +###Type Parameters |
| 44 | +There's one problem with our type hierarchy - it's way too narrow to only define lists with `Int` elements. If we did it that way, we'd need a type hierarchy for `Double`, `Boolean`, and so on... |
| 45 | + |
| 46 | +What we need to do is generalize the definition - we can do that using the `type` parameter |
| 47 | + |
| 48 | +```scala |
| 49 | +trait List[T] |
| 50 | +class Cons[T](val: head T, val tail: List[T]) extends List[T] |
| 51 | +class Nil[T] extends List[T] |
| 52 | +``` |
| 53 | + |
| 54 | +So, we're going to define a base trait, List, which takes a type parameter `T`. That base trait List[T] will have two subclasses, `Cons[T]` and `Nil[T]`. `Cons[T]` will now have a head element of type `T`, and a tail element of type `List[T]` |
| 55 | + |
| 56 | +###Generic Functions |
| 57 | +Like classes, functions can have type parameters. For instance, here's a function that creates a list consisting of a single element: |
| 58 | + |
| 59 | +```scala |
| 60 | +def singleton[T](elem: T) = new Cons[T](elem, new Nil[T]) |
| 61 | +``` |
| 62 | + |
| 63 | +We can then write: |
| 64 | + |
| 65 | +```scala |
| 66 | +singleton[Int](1) |
| 67 | +singleton[Boolean](true) |
| 68 | +``` |
| 69 | + |
| 70 | +###Type Inference |
| 71 | +The scala compiler can usually deduce the correct type parameters from the value arguments of a function call - so in most cases the type parameters can be left out. The above could just be written as: |
| 72 | + |
| 73 | +```scala |
| 74 | +singleton(1) |
| 75 | +singleton(true) |
| 76 | +``` |
| 77 | + |
| 78 | +###Types and Evaluation |
| 79 | + |
| 80 | +Type parameters do not affect evaluation in scala at all - we can assume that all type parameters and type arguments are removed before evaluation of the program. This is called *type erasure*. Types are only important for the compiler to verify that the program satisfies certain correctness properties, but they're not relevant for the actual execution. |
| 81 | + |
| 82 | +###Polymorphism |
| 83 | +Polymorphism means that a function type comes "in many forms" - basically, the function can be applied to arguments of many types, or the type can have instances of many types. |
| 84 | + |
| 85 | +We have seen two principle forms of polymorphism - subtyping, and generics. |
| 86 | + |
| 87 | +Subtyping means that instances of a subclass can be passed to a base class - ie, given our `List` hierarchy, anywhere we have a parameter that accepts type `List`, we can pass either a `Nil` or a `Cons`. |
| 88 | + |
| 89 | +Generics means that we can create many instances of a function or class by type parameterization. By using generics, we could create a `List[Int]`, or a `List[List[Boolean]]`, whatever dawg. |
0 commit comments