TI1220 Lecture 8: Traits & Type Parameterization

1,313 views

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,313
On SlideShare
0
From Embeds
0
Number of Embeds
671
Actions
Shares
0
Downloads
27
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

TI1220 Lecture 8: Traits & Type Parameterization

  1. 1. TI1220 2012-2013Concepts of Programming LanguagesEelco Visser / TU DelftLecture 8: Traits & Type Parameterization
  2. 2. var ms := course.managers;var ms : Set<Person> := Set<Person>();ms.addAll(course.managers);Analysis => Lecture 12: ConcurrencyRoot CauseThe FixIntention: copysemanticsEffect: referencesemanticsThe Fault: Concurrent writes on CourseEdition
  3. 3. The Airconditioning
  4. 4. Syntax and SemanticsNames, Bindings, and ScopesStorageData TypesFunctional ProgrammingFirst-class FunctionsPolymorphismTraits & Type ParameterizationParsing and InterpretationData Abstraction / Modular ProgrammingFunctional Programming ReduxConcurrencyConcurrent ProgrammingDomain-Specific LanguagesQuarter 3Quarter 4Basics ofScalaJavaScriptC
  5. 5. Traits
  6. 6. abstract class Element {def contents: Array[String]def height: Int = contents.lengthdef width: Int = if (height == 0) 0else contents(0).length}class ArrayElement(conts: Array[String]) extends Element {val contents: Array[String] = conts}Classical InheritanceInheriting fields and methods
  7. 7. class UniformElement(ch: Char,override val width: Int,override val height: Int) extends Element {private val line = ch.toString * widthdef contents = Array.make(height, line)}val e1: Element = new ArrayElement(Array("hello", "world"))val ae: ArrayElement = new LineElement("hello")val e2: Element = aeval e3: Element = new UniformElement(x, 2, 3)Subtyping
  8. 8. abstract class Element {def demo() {println("Elements implementation invoked")}}class ArrayElement extends Element {override def demo() {println("ArrayElements implementation invoked")}}class LineElement extends ArrayElement {override def demo() {println("LineElements implementation invoked")}}// UniformElement inherits Element’s democlass UniformElement extends Elementdef invokeDemo(e: Element) {e.demo()}scala> invokeDemo(new ArrayElement)ArrayElements implementation invokedscala> invokeDemo(new LineElement)LineElements implementation invokedscala> invokeDemo(new UniformElement)Elements implementation invokedDynamic Binding
  9. 9. Subtyping• Polymorphism & dynamic bindingCode Reuse• reuse instance variables and methods from super classSingle Inheritance• cannot reuse code from more than one classInterfaces• support subtyping multiple classes• must re-implement interfaceJava-style Single Inheritance
  10. 10. Trait• reusable unit of code• encapsulates method and field definitions• reused by mixing into classes• class can mix in any number of traitsApplications• rich interfaces• stackable modifications
  11. 11. trait Philosophical {def philosophize() {println("I consume memory, therefore I am!")}}class Frog extends Philosophical {override def toString = "green"}scala> val frog = new Frogfrog: Frog = greenscala> frog.philosophize()I consume memory, therefore I am!scala> val phil: Philosophical = frogphil: Philosophical = greenscala> phil.philosophize()I consume memory, therefore I am!inheritance: code reuse subtyping: traits are typesDefining and Using Traits
  12. 12. class Animaltrait HasLegsclass Frog extends Animal with Philosophical with HasLegs {override def toString = "green"override def philosophize() {println("It aint easy being " + toString + "!")}}superclasstraitsoverride code from traitscala> val phrog: Philosophical = new Frogphrog: Philosophical = greenscala> phrog.philosophize()It aint easy being green!Mixing in (multiple) traits
  13. 13. Trait is like Java interface with• methods• fields• stateTrait is Scala class• without class parameters• dynamic binding of ‘super’
  14. 14. Rich interface• many methods• convenient for client• more work for implementerThin interface• few methods• easy for implementers• inconvenient for clienttrait CharSequence {def charAt(index: Int): Chardef length: Intdef subSequence(start: Int, end: Int): CharSequencedef toString(): String}Rich Interfaces with Traits• small number of abstractmethods implemented byclient• large number of concretemethods inherited by client
  15. 15. class Point(val x: Int, val y: Int)class Rectangle(val topLeft: Point, val bottomRight: Point){def left = topLeft.xdef right = bottomRight.xdef width = right - left// and many more geometric methods...}abstract class Component {def topLeft: Pointdef bottomRight: Pointdef left = topLeft.xdef right = bottomRight.xdef width = right - left// and many more geometric methods...}Rectangular objects without traits
  16. 16. trait Rectangular {def topLeft: Pointdef bottomRight: Pointdef left = topLeft.xdef right = bottomRight.xdef width = right - left// and many more geometric methods...}abstract class Component extends Rectangular {// other methods...}class Rectangle(val topLeft: Point, val bottomRight: Point)extends Rectangular {// other methods...}Rectangular objects with traits
  17. 17. trait Rectangular {def topLeft: Pointdef bottomRight: Pointdef left = topLeft.xdef right = bottomRight.xdef width = right - left// and many more geometric methods...}abstract class Component extends Rectangular {// other methods...}class Rectangle(val topLeft: Point, val bottomRight: Point)extends Rectangular {// other methods...}scala> val rect = new Rectangle(new Point(1, 1),new Point(10, 10))rect: Rectangle = Rectangle@3536fdscala> rect.leftres2: Int = 1scala> rect.rightres3: Int = 10Rectangular objects with traits
  18. 18. class Rational(n: Int, d: Int) {// ...def <(that: Rational) =this.numer * that.denom > that.numer * this.denomdef >(that: Rational) = that < thisdef <=(that: Rational) = (this < that) || (this == that)def >=(that: Rational) = (this > that) || (this == that)}defined in terms of <based on standardsemantics of ordering{A Rich Interface for Ordering
  19. 19. class Rational(n: Int, d: Int) {// ...def <(that: Rational) =this.numer * that.denom > that.numer * this.denomdef >(that: Rational) = that < thisdef <=(that: Rational) = (this < that) || (this == that)def >=(that: Rational) = (this > that) || (this == that)}defined in terms of <based on standardsemantics of ordering{class Rational(n: Int, d: Int) extends Ordered[Rational] {// ...def compare(that: Rational) =(this.numer * that.denom) - (that.numer * this.denom)}A Rich Interface for Ordering
  20. 20. class Rational(n: Int, d: Int) {// ...def <(that: Rational) =this.numer * that.denom > that.numer * this.denomdef >(that: Rational) = that < thisdef <=(that: Rational) = (this < that) || (this == that)def >=(that: Rational) = (this > that) || (this == that)}defined in terms of <based on standardsemantics of ordering{class Rational(n: Int, d: Int) extends Ordered[Rational] {// ...def compare(that: Rational) =(this.numer * that.denom) - (that.numer * this.denom)}Ordered trait provides reusableimplementation of orderingA Rich Interface for Ordering
  21. 21. Class Queue of integers• put: place integer in queue• get: take integer out• first-in first-outModifications• Doubling: double all integers put in queue• Incrementing: increment all integers put in queue• Filtering: filter out negativeStackable Modifications
  22. 22. abstract class IntQueue {def get(): Intdef put(x: Int)}import scala.collection.mutable.ArrayBufferclass BasicIntQueue extends IntQueue {private val buf = new ArrayBuffer[Int]def get() = buf.remove(0)def put(x: Int) { buf += x }}Class Queue
  23. 23. abstract class IntQueue {def get(): Intdef put(x: Int)}import scala.collection.mutable.ArrayBufferclass BasicIntQueue extends IntQueue {private val buf = new ArrayBuffer[Int]def get() = buf.remove(0)def put(x: Int) { buf += x }}scala> val queue = new BasicIntQueuequeue: BasicIntQueue = BasicIntQueue@24655fscala> queue.put(10)scala> queue.put(20)scala> queue.get()res9: Int = 10scala> queue.get()res10: Int = 20Class Queue
  24. 24. trait Doubling extends IntQueue {abstract override def put(x: Int) { super.put(2 * x) }}dynamically boundcan only be mixed intosubclasses of IntQueuemix into classwith concretedefinitionTrait Doubling
  25. 25. trait Doubling extends IntQueue {abstract override def put(x: Int) { super.put(2 * x) }}dynamically boundcan only be mixed intosubclasses of IntQueuemix into classwith concretedefinitionscala> class MyQueue extends BasicIntQueue with Doublingdefined class MyQueuescala> val queue = new MyQueuequeue: MyQueue = MyQueue@91f017scala> queue.put(10)scala> queue.get()res12: Int = 20Trait Doubling
  26. 26. trait Doubling extends IntQueue {abstract override def put(x: Int) { super.put(2 * x) }}dynamically boundcan only be mixed intosubclasses of IntQueuemix into classwith concretedefinitionscala> class MyQueue extends BasicIntQueue with Doublingdefined class MyQueuescala> val queue = new MyQueuequeue: MyQueue = MyQueue@91f017scala> queue.put(10)scala> queue.get()res12: Int = 20scala> val queue = new BasicIntQueue with Doublingqueue: BasicIntQueue with Doubling = $anon$1@5fa12dscala> queue.put(10)scala> queue.get()res14: Int = 20Trait Doubling
  27. 27. trait Incrementing extends IntQueue {abstract override def put(x: Int) { super.put(x + 1) }}trait Filtering extends IntQueue {abstract override def put(x: Int) {if (x >= 0) super.put(x)}}Stacking Modifications
  28. 28. trait Incrementing extends IntQueue {abstract override def put(x: Int) { super.put(x + 1) }}trait Filtering extends IntQueue {abstract override def put(x: Int) {if (x >= 0) super.put(x)}}scala> val queue = (new BasicIntQueuewith Incrementingwith Filtering)scala> queue.put(-1);queue.put(0);queue.put(1)scala> queue.get()res15: Int = 1scala> queue.get()res15: Int = 2Stacking Modifications
  29. 29. trait Incrementing extends IntQueue {abstract override def put(x: Int) { super.put(x + 1) }}trait Filtering extends IntQueue {abstract override def put(x: Int) {if (x >= 0) super.put(x)}}scala> val queue = (new BasicIntQueuewith Incrementingwith Filtering)scala> queue.put(-1);queue.put(0);queue.put(1)scala> queue.get()res15: Int = 1scala> queue.get()res15: Int = 2Stacking Modificationsscala> val queue = (new BasicIntQueuewith Filteringwith Incrementing)scala> queue.put(-1);queue.put(0);queue.put(1)scala> queue.get()res17: Int = 0scala> queue.get()res18: Int = 1scala> queue.get()res19: Int = 2
  30. 30. // Multiple inheritance thought experimentval q = new BasicIntQueue with Incrementing with Doublingq.put(42) // which put would be called?Multiple Inheritance (Why Not?)Incrementing DoublingBasicIntQueuenew BasicIntQueue withIncrement with Doubling
  31. 31. // Multiple inheritance thought experimenttrait MyQueue extends BasicIntQueuewith Incrementing with Doubling {def put(x: Int) {Incrementing.super.put(x)// (Not real Scala)Doubling.super.put(x)}}Multiple Inheritance (Why Not?)Incrementing DoublingBasicIntQueuenew BasicIntQueue withIncrement with Doublingput of BasicIntQuecalled twice!
  32. 32. a class is always linearized before allof its superclasses and mixed in traitsclass Animaltrait Furry extends Animaltrait HasLegs extends Animaltrait FourLegged extends HasLegsclass Cat extends Animal with Furry with FourLeggedLinearly Ordering Traits
  33. 33. Units of code• reusable through inheritance• can be mixed in at multiple places in hierarchyMultiple inheritance ++• calls to super are linearized• avoid diamond problem• stack changesTraits Summary
  34. 34. What is the value of question in:class Animal {override def toString = "Animal"}trait Furry extends Animal {override def toString = "Furry -> " + super.toString}trait HasLegs extends Animal {override def toString = "HasLegs -> " + super.toString}trait FourLegged extends HasLegs {override def toString = "FourLegged -> " + super.toString}class Cat extends Animal with Furry with FourLegged {override def toString = "Cat -> " + super.toString}val question = new Cata) Cat -> FourLegged -> HasLegs -> Furry -> Animalb) Cat -> HasLegs -> FourLegged -> Furry -> Animalc) Cat -> Furry -> FourLegged -> HasLegs -> Animald) Cat -> Furry -> HasLegs -> FourLegged -> AnimalTraits Experiment
  35. 35. Type Parameterization
  36. 36. def append[T](xs: List[T], ys: List[T]): List[T] =xs match {case List() => yscase x :: xs1 => x :: append(xs1, ys)}
  37. 37. def map[A,B](xs: List[A], f: A => B): List[B] = xs match {case List() => List()case y :: ys => f(y) :: map(ys, f)}
  38. 38. Generic classes and traits• Set[T]: generic sets parameterized with type T• Set[Int]: set of integers, instance of Set[T]• No raw types: always use with type parameterExample: Functional Queues
  39. 39. typedef struct queue_elem {int val;struct queue_elem *next;} queue_elem;typedef struct queue {queue_elem *first;queue_elem *last;} queue;queue *newQueue() {queue *q = (queue *)malloc(sizeof(queue));q->first = NULL;q->last = NULL;return q;}Imperative Queue in C
  40. 40. void enqueue(queue *q, int val) {queue_elem *elem = (queue_elem *)malloc(sizeof(queue_elem));elem->val = val;elem->next = NULL;if(q->first == NULL) {q->first = q->last = elem;} else {q->last->next = elem;q->last = elem;}}Imperative Queue in C
  41. 41. int dequeue(queue *q) {if(q == NULL || q->first == NULL) {return 0;}int val = q->first->val;queue_elem *elem = q->first;if(q->first == q->last) {q->last = NULL;}q->first = q->first->next;free(elem);return val;}Imperative Queue in C
  42. 42. Queue operations• head: return first element• tail: return rest• append: new queue with new element at the endFunctional Queue• fully persistent• contents not changed when appending• efficient implementation should be O(1) for all operationsscala> val q = Queue(1, 2, 3)q: Queue[Int] = Queue(1, 2, 3)scala> val q1 = q append 4q1: Queue[Int] = Queue(1, 2, 3, 4)scala> qres0: Queue[Int] = Queue(1, 2, 3)Functional Queue
  43. 43. class SlowAppendQueue[T](elems: List[T]) { // Not efficientdef head = elems.headdef tail = new SlowAppendQueue(elems.tail)def append(x: T) = new SlowAppendQueue(elems ::: List(x))}Functional Queue (First Attempt)
  44. 44. class SlowAppendQueue[T](elems: List[T]) { // Not efficientdef head = elems.headdef tail = new SlowAppendQueue(elems.tail)def append(x: T) = new SlowAppendQueue(elems ::: List(x))}append = O(n)Functional Queue (First Attempt)
  45. 45. class SlowAppendQueue[T](elems: List[T]) { // Not efficientdef head = elems.headdef tail = new SlowAppendQueue(elems.tail)def append(x: T) = new SlowAppendQueue(elems ::: List(x))}class SlowHeadQueue[T](smele: List[T]) { // Not efficient// smele is elems reverseddef head = smele.lastdef tail = new SlowHeadQueue(smele.init)def append(x: T) = new SlowHeadQueue(x :: smele)}append = O(n)Functional Queue (First Attempt)
  46. 46. class SlowAppendQueue[T](elems: List[T]) { // Not efficientdef head = elems.headdef tail = new SlowAppendQueue(elems.tail)def append(x: T) = new SlowAppendQueue(elems ::: List(x))}class SlowHeadQueue[T](smele: List[T]) { // Not efficient// smele is elems reverseddef head = smele.lastdef tail = new SlowHeadQueue(smele.init)def append(x: T) = new SlowHeadQueue(x :: smele)}append = O(n)head, tail = O(n)Functional Queue (First Attempt)
  47. 47. class SlowAppendQueue[T](elems: List[T]) { // Not efficientdef head = elems.headdef tail = new SlowAppendQueue(elems.tail)def append(x: T) = new SlowAppendQueue(elems ::: List(x))}class SlowHeadQueue[T](smele: List[T]) { // Not efficient// smele is elems reverseddef head = smele.lastdef tail = new SlowHeadQueue(smele.init)def append(x: T) = new SlowHeadQueue(x :: smele)}append = O(n)head, tail = O(n)head, tail, append = O(1) cannot be possible!Functional Queue (First Attempt)
  48. 48. class Queue[T](private val leading: List[T],private val trailing: List[T]) {def head = leading.headdef tail = new Queue(leading.tail, trailing)def append(x: T) = new Queue(leading, x :: trailing)}elems == leading ::: trailing.reverseRepresent Queue with Two Lists
  49. 49. class Queue[T](private val leading: List[T],private val trailing: List[T]) {def head = leading.headdef tail = new Queue(leading.tail, trailing)def append(x: T) = new Queue(leading, x :: trailing)}elems == leading ::: trailing.reversebut what if leading.isEmpty?Represent Queue with Two Lists
  50. 50. Mirroringclass Queue[T](private val leading: List[T],private val trailing: List[T]) {private def mirror =if (leading.isEmpty)new Queue(trailing.reverse, Nil)elsethisdef head = mirror.leading.headdef tail = {val q = mirrornew Queue(q.leading.tail, q.trailing)}def append(x: T) =new Queue(leading, x :: trailing)}
  51. 51. Mirroringclass Queue[T](private val leading: List[T],private val trailing: List[T]) {private def mirror =if (leading.isEmpty)new Queue(trailing.reverse, Nil)elsethisdef head = mirror.leading.headdef tail = {val q = mirrornew Queue(q.leading.tail, q.trailing)}def append(x: T) =new Queue(leading, x :: trailing)}head, tail, append: O(1)mirror: O(n)but amortized over n calls of tail
  52. 52. Mirroringclass Queue[T](private val leading: List[T],private val trailing: List[T]) {private def mirror =if (leading.isEmpty)new Queue(trailing.reverse, Nil)elsethisdef head = mirror.leading.headdef tail = {val q = mirrornew Queue(q.leading.tail, q.trailing)}def append(x: T) =new Queue(leading, x :: trailing)}head, tail, append: O(1)mirror: O(n)but amortized over n calls of tailimplementation is exposed!
  53. 53. class Queue[T] private (private val leading: List[T],private val trailing: List[T]) {def this() = this(Nil, Nil)def this(elems: T*) = this(elems.toList, Nil)def head = ...def tail = ...def append(x: T) = ...}scala> Queue(1, 2, 3)private parameterspublic auxiliary constructorshide implementationdetails from clientsPrivate Constructors
  54. 54. class Queue[T] private (private val leading: List[T],private val trailing: List[T]) {def head = ...def tail = ...def append(x: T) = ...}object Queue {// constructs a queue with initial elements ‘xs’def apply[T](xs: T*) = new Queue[T](xs.toList, Nil)}Factory Method hide implementationdetails from clientsfactory methodprivate parameters
  55. 55. trait Queue[T] {def head: Tdef tail: Queue[T]def append(x: T): Queue[T]}object Queue {def apply[T](xs: T*): Queue[T] = new QueueImpl[T](xs.toList, Nil)private class QueueImpl[T](private val leading: List[T],private val trailing: List[T]) extends Queue[T] {def mirror =if (leading.isEmpty) new QueueImpl(trailing.reverse, Nil)else thisdef head: T = mirror.leading.headdef tail: QueueImpl[T] = {val q = mirrornew QueueImpl(q.leading.tail, q.trailing)}def append(x: T) = new QueueImpl(leading, x :: trailing)}}hide implementationdetails from clients
  56. 56. scala> def doesNotCompile(q: Queue) {}<console>:5: error: trait Queue takes type parametersdef doesNotCompile(q: Queue) {}scala> def doesCompile(q: Queue[AnyRef]) {}doesCompile: (Queue[AnyRef])UnitQueue is a trait, not a typeQueue is a type constructor or generic traitQueue[String] is a (specific) typeGeneric Traits
  57. 57. Queue[String] subtype of Queue[AnyRef] ?if S subtype of T then Queue[S] subtype of Queue[T] ?If answer is yes: Queue is covariant in Ttrait Queue[+T] { ... }val q: Queue[AnyRef] = Queue[String](“a”)If answer is no: Queue is contravariant in Ttrait Queue[-T] { ... }val q: Queue[String] = Queue[AnyRef]()default: nonvariantSubtyping &Variance Annotations
  58. 58. class Cell[+T](init: T) {private[this] var current = initdef get = currentdef set(x: T) { current = x }}val c1 = new Cell[String]("abc")val c2: Cell[Any] = c1c2.set(1)val s: String = c1.getCovariance and Mutable Classes
  59. 59. class Cell[+T](init: T) {private[this] var current = initdef get = currentdef set(x: T) { current = x }}val c1 = new Cell[String]("abc")val c2: Cell[Any] = c1c2.set(1)val s: String = c1.getCell.scala:7: error: covariant type T occurs incontravariant position in type T of value xdef set(x: T) = current = xCovariance and Mutable Classes
  60. 60. package society {package professional {class Executive {private[professional] var workDetails = nullprivate[society] var friends = nullprivate[this] var secrets = nulldef help(another : Executive) {println(another.workDetails)println(another.secrets) //ERROR}}}}Source: http://www.tutorialspoint.com/scala/scala_access_modifiers.htmScope of Protection of Access ModifiersA private member is visible only inside the class or object that contains the member definition.A protected member is only accessible from subclasses of the class in which the member is defined.Every member not labeled private or protected is public. There is no explicit modifier for public members.Such members can be accessed from anywhere.
  61. 61. // this is JavaString[] a1 = { "abc" };Object[] a2 = a1;a2[0] = new Integer(17);String s = a1[0];no compile-time errorVariance and Arrays
  62. 62. // this is JavaString[] a1 = { "abc" };Object[] a2 = a1;a2[0] = new Integer(17);String s = a1[0];Exception in thread "main" java.lang.ArrayStoreException:java.lang.Integer at JavaArrays.main(JavaArrays.java:8)no compile-time errorVariance and Arrays
  63. 63. // this is JavaString[] a1 = { "abc" };Object[] a2 = a1;a2[0] = new Integer(17);String s = a1[0];Exception in thread "main" java.lang.ArrayStoreException:java.lang.Integer at JavaArrays.main(JavaArrays.java:8)no compile-time errormotivation: generic treatment of arrays:void sort(Object[] a, Comparator cmp) { ... }Variance and Arrays
  64. 64. scala> val a1 = Array("abc")a1: Array[java.lang.String] = Array(abc)scala> val a2: Array[Any] = a1<console>:5: error: type mismatch;found : Array[java.lang.String]required: Array[Any]val a2: Array[Any] = a1ˆscala> val a2: Array[Object] =a1.asInstanceOf[Array[Object]]a2: Array[java.lang.Object] = Array(abc)Scala Arrays are Non-variant
  65. 65. class Queue[+T] {def append(x: T) =...}class StrangeIntQueue extends Queue[Int] {override def append(x: Int) = {println(Math.sqrt(x))super.append(x)}}val x: Queue[Any] = new StrangeIntQueuex.append("abc")CheckingVariance Annotations
  66. 66. class Queue[+T] {def append(x: T) =...}class StrangeIntQueue extends Queue[Int] {override def append(x: Int) = {println(Math.sqrt(x))super.append(x)}}val x: Queue[Any] = new StrangeIntQueuex.append("abc")Queues.scala:11: error: covariant type T occurs incontravariant position in type T of value xdef append(x: T) =ˆCheckingVariance Annotations
  67. 67. class Queue[+T](private val leading: List[T],private val trailing: List[T]) {def append[U >: T](x: U) =new Queue[U](leading, x :: trailing) // ...}class Fruitclass Apple extends Fruitclass Orange extends Fruitscala> val qa = Queue(new Apple)scala> val qb = qa.append(new Orange)qb: Queue[Fruit] = ...U >: T == U is a supertype of TLower Bounds
  68. 68. class Queue[+T] private (private[this] var leading: List[T],private[this] var trailing: List[T]) {private def mirror() =if (leading.isEmpty) {while (!trailing.isEmpty) {leading = trailing.head :: leadingtrailing = trailing.tail}}def head: T = {mirror(); leading.head}def tail: Queue[T] = {mirror();new Queue(leading.tail, trailing)}def append[U >: T](x: U) =new Queue[U](leading, x :: trailing)}Optimized Functional Queue
  69. 69. def orderedMergeSort[T <: Ordered[T]](xs: List[T]): List[T] = {def merge(xs: List[T], ys: List[T]): List[T] =(xs, ys) match {case (Nil, _) => yscase (_, Nil) => xscase (x :: xs1, y :: ys1) =>if (x < y) x :: merge(xs1, ys)else y :: merge(xs, ys1)}val n = xs.length / 2if (n == 0) xselse {val (ys, zs) = xs splitAt nmerge(orderedMergeSort(ys), orderedMergeSort(zs))}}Upperbounds
  70. 70. Information hiding• private constructors• factory methods• object private membersType variance• subtyping of generic types• covariant, contravariant variance annotations• lower bounds, upper boundsType Parameterization Summary
  71. 71. Reading & Programming in Week 6ReadingScala Chapter 12: TraitsScala Chapter 19: Type ParameterizationWeek 9: Parsers and InterpretersWebLab:Graded Assignment 2: (deadline 14 May 2013, 23:59)

×