ti1220 lecture 8: traits & type parameterization
TRANSCRIPT
![Page 1: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/1.jpg)
TI1220 2012-2013Concepts of Programming Languages
Eelco Visser / TU Delft
Lecture 8: Traits & Type Parameterization
![Page 2: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/2.jpg)
var ms := course.managers;
var ms : Set<Person> := Set<Person>();ms.addAll(course.managers);
Analysis => Lecture 12: Concurrency
Root Cause
The Fix
Intention: copy semantics
Effect: reference semantics
The Fault: Concurrent writes on CourseEdition
![Page 3: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/3.jpg)
The Airconditioning
![Page 4: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/4.jpg)
Syntax and SemanticsNames, Bindings, and Scopes Storage Data TypesFunctional ProgrammingFirst-class FunctionsPolymorphism
Traits & Type ParameterizationParsing and InterpretationData Abstraction / Modular ProgrammingFunctional Programming ReduxConcurrencyConcurrent ProgrammingDomain-Specific Languages
Quarter 3
Quarter 4
Basics ofScalaJavaScriptC
![Page 5: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/5.jpg)
Traits
![Page 6: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/6.jpg)
abstract class Element { def contents: Array[String] def height: Int = contents.length def width: Int = if (height == 0) 0 else contents(0).length}
class ArrayElement(conts: Array[String]) extends Element { val contents: Array[String] = conts}
Classical Inheritance
Inheriting fields and methods
![Page 7: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/7.jpg)
class UniformElement( ch: Char, override val width: Int, override val height: Int) extends Element { private val line = ch.toString * width def 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
![Page 8: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/8.jpg)
abstract class Element { def demo() { println("Element's implementation invoked") }}class ArrayElement extends Element { override def demo() { println("ArrayElement's implementation invoked") }}class LineElement extends ArrayElement { override def demo() { println("LineElement's implementation invoked") }}// UniformElement inherits Element’s democlass UniformElement extends Element
def invokeDemo(e: Element) { e.demo()}scala> invokeDemo(new ArrayElement)ArrayElement's implementation invoked
scala> invokeDemo(new LineElement)LineElement's implementation invoked
scala> invokeDemo(new UniformElement)Element's implementation invoked
Dynamic Binding
![Page 9: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/9.jpg)
Subtyping
• Polymorphism & dynamic binding
Code Reuse
• reuse instance variables and methods from super class
Single Inheritance
• cannot reuse code from more than one class
Interfaces
• support subtyping multiple classes
• must re-implement interface
Java-style Single Inheritance
![Page 10: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/10.jpg)
Trait
• reusable unit of code
• encapsulates method and field definitions
• reused by mixing into classes
• class can mix in any number of traits
Applications
• rich interfaces
• stackable modifications
![Page 11: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/11.jpg)
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 types
Defining and Using Traits
![Page 12: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/12.jpg)
class Animaltrait HasLegsclass Frog extends Animal with Philosophical with HasLegs { override def toString = "green" override def philosophize() { println("It ain't easy being " + toString + "!") }}
superclasstraits
override code from traitscala> val phrog: Philosophical = new Frogphrog: Philosophical = greenscala> phrog.philosophize()It ain't easy being green!
Mixing in (multiple) traits
![Page 13: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/13.jpg)
Trait is like Java interface with
• methods
• fields
• state
Trait is Scala class
• without class parameters
• dynamic binding of ‘super’
![Page 14: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/14.jpg)
Rich interface
• many methods
• convenient for client
• more work for implementer
Thin interface
• few methods
• easy for implementers
• inconvenient for client
trait CharSequence { def charAt(index: Int): Char def length: Int def subSequence(start: Int, end: Int): CharSequence def toString(): String}
Rich Interfaces with Traits
• small number of abstract methods implemented by client
• large number of concrete methods inherited by client
![Page 15: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/15.jpg)
class Point(val x: Int, val y: Int)class Rectangle(val topLeft: Point, val bottomRight: Point) { def left = topLeft.x def right = bottomRight.x def width = right - left // and many more geometric methods...}
abstract class Component { def topLeft: Point def bottomRight: Point def left = topLeft.x def right = bottomRight.x def width = right - left // and many more geometric methods...}
Rectangular objects without traits
![Page 16: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/16.jpg)
trait Rectangular { def topLeft: Point def bottomRight: Point def left = topLeft.x def right = bottomRight.x def 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
![Page 17: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/17.jpg)
trait Rectangular { def topLeft: Point def bottomRight: Point def left = topLeft.x def right = bottomRight.x def 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 = 10
Rectangular objects with traits
![Page 18: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/18.jpg)
class Rational(n: Int, d: Int) { // ... def <(that: Rational) = this.numer * that.denom > that.numer * this.denom def >(that: Rational) = that < this def <=(that: Rational) = (this < that) || (this == that) def >=(that: Rational) = (this > that) || (this == that)}
defined in terms of < based on standard
semantics of ordering
{
A Rich Interface for Ordering
![Page 19: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/19.jpg)
class Rational(n: Int, d: Int) { // ... def <(that: Rational) = this.numer * that.denom > that.numer * this.denom def >(that: Rational) = that < this def <=(that: Rational) = (this < that) || (this == that) def >=(that: Rational) = (this > that) || (this == that)}
defined in terms of < based on standard
semantics 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
![Page 20: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/20.jpg)
class Rational(n: Int, d: Int) { // ... def <(that: Rational) = this.numer * that.denom > that.numer * this.denom def >(that: Rational) = that < this def <=(that: Rational) = (this < that) || (this == that) def >=(that: Rational) = (this > that) || (this == that)}
defined in terms of < based on standard
semantics 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 reusable implementation of ordering
A Rich Interface for Ordering
![Page 21: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/21.jpg)
Class Queue of integers
• put: place integer in queue
• get: take integer out
• first-in first-out
Modifications
• Doubling: double all integers put in queue
• Incrementing: increment all integers put in queue
• Filtering: filter out negative
Stackable Modifications
![Page 22: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/22.jpg)
abstract class IntQueue { def get(): Int def 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
![Page 23: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/23.jpg)
abstract class IntQueue { def get(): Int def 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@24655f
scala> queue.put(10)
scala> queue.put(20)
scala> queue.get()res9: Int = 10
scala> queue.get()res10: Int = 20
Class Queue
![Page 24: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/24.jpg)
trait Doubling extends IntQueue { abstract override def put(x: Int) { super.put(2 * x) }}
dynamically bound
can only be mixed into subclasses of IntQueue
mix into class with concrete
definition
Trait Doubling
![Page 25: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/25.jpg)
trait Doubling extends IntQueue { abstract override def put(x: Int) { super.put(2 * x) }}
dynamically bound
can only be mixed into subclasses of IntQueue
mix into class with concrete
definition
scala> class MyQueue extends BasicIntQueue with Doublingdefined class MyQueue
scala> val queue = new MyQueuequeue: MyQueue = MyQueue@91f017
scala> queue.put(10)
scala> queue.get()res12: Int = 20
Trait Doubling
![Page 26: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/26.jpg)
trait Doubling extends IntQueue { abstract override def put(x: Int) { super.put(2 * x) }}
dynamically bound
can only be mixed into subclasses of IntQueue
mix into class with concrete
definition
scala> class MyQueue extends BasicIntQueue with Doublingdefined class MyQueue
scala> val queue = new MyQueuequeue: MyQueue = MyQueue@91f017
scala> queue.put(10)
scala> queue.get()res12: Int = 20
scala> val queue = new BasicIntQueue with Doublingqueue: BasicIntQueue with Doubling = $anon$1@5fa12d
scala> queue.put(10)
scala> queue.get()res14: Int = 20
Trait Doubling
![Page 27: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/27.jpg)
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
![Page 28: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/28.jpg)
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 BasicIntQueue with Incrementing with Filtering)scala> queue.put(-1); queue.put(0); queue.put(1)
scala> queue.get()res15: Int = 1scala> queue.get()res15: Int = 2
Stacking Modifications
![Page 29: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/29.jpg)
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 BasicIntQueue with Incrementing with Filtering)scala> queue.put(-1); queue.put(0); queue.put(1)
scala> queue.get()res15: Int = 1scala> queue.get()res15: Int = 2
Stacking Modifications
scala> val queue = (new BasicIntQueue with Filtering with 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
![Page 30: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/30.jpg)
// Multiple inheritance thought experimentval q = new BasicIntQueue with Incrementing with Doublingq.put(42) // which put would be called?
Multiple Inheritance (Why Not?)
Incrementing Doubling
BasicIntQueue
new BasicIntQueue with Increment with Doubling
![Page 31: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/31.jpg)
// Multiple inheritance thought experimenttrait MyQueue extends BasicIntQueue with Incrementing with Doubling { def put(x: Int) { Incrementing.super.put(x) // (Not real Scala) Doubling.super.put(x) }}
Multiple Inheritance (Why Not?)
Incrementing Doubling
BasicIntQueue
new BasicIntQueue with Increment with Doubling
put of BasicIntQue called twice!
![Page 32: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/32.jpg)
a class is always linearized before all of its superclasses and mixed in traits
class Animaltrait Furry extends Animaltrait HasLegs extends Animaltrait FourLegged extends HasLegsclass Cat extends Animal with Furry with FourLegged
Linearly Ordering Traits
![Page 33: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/33.jpg)
Units of code
• reusable through inheritance
• can be mixed in at multiple places in hierarchy
Multiple inheritance ++
• calls to super are linearized
• avoid diamond problem
• stack changes
Traits Summary
![Page 34: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/34.jpg)
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 Cat
a) Cat -> FourLegged -> HasLegs -> Furry -> Animalb) Cat -> HasLegs -> FourLegged -> Furry -> Animalc) Cat -> Furry -> FourLegged -> HasLegs -> Animald) Cat -> Furry -> HasLegs -> FourLegged -> Animal
Traits Experiment
![Page 35: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/35.jpg)
Type Parameterization
![Page 36: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/36.jpg)
def append[T](xs: List[T], ys: List[T]): List[T] = xs match { case List() => ys case x :: xs1 => x :: append(xs1, ys) }
![Page 37: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/37.jpg)
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)}
![Page 38: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/38.jpg)
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 parameter
Example: Functional Queues
![Page 39: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/39.jpg)
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
![Page 40: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/40.jpg)
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
![Page 41: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/41.jpg)
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
![Page 42: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/42.jpg)
Queue operations
• head: return first element
• tail: return rest
• append: new queue with new element at the end
Functional Queue
• fully persistent
• contents not changed when appending
• efficient implementation should be O(1) for all operations
scala> 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
![Page 43: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/43.jpg)
class SlowAppendQueue[T](elems: List[T]) { // Not efficient def head = elems.head def tail = new SlowAppendQueue(elems.tail) def append(x: T) = new SlowAppendQueue(elems ::: List(x))}
Functional Queue (First Attempt)
![Page 44: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/44.jpg)
class SlowAppendQueue[T](elems: List[T]) { // Not efficient def head = elems.head def tail = new SlowAppendQueue(elems.tail) def append(x: T) = new SlowAppendQueue(elems ::: List(x))}
append = O(n)
Functional Queue (First Attempt)
![Page 45: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/45.jpg)
class SlowAppendQueue[T](elems: List[T]) { // Not efficient def head = elems.head def 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 reversed def head = smele.last def tail = new SlowHeadQueue(smele.init) def append(x: T) = new SlowHeadQueue(x :: smele)}
append = O(n)
Functional Queue (First Attempt)
![Page 46: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/46.jpg)
class SlowAppendQueue[T](elems: List[T]) { // Not efficient def head = elems.head def 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 reversed def head = smele.last def tail = new SlowHeadQueue(smele.init) def append(x: T) = new SlowHeadQueue(x :: smele)}
append = O(n)
head, tail = O(n)
Functional Queue (First Attempt)
![Page 47: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/47.jpg)
class SlowAppendQueue[T](elems: List[T]) { // Not efficient def head = elems.head def 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 reversed def head = smele.last def 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)
![Page 48: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/48.jpg)
class Queue[T]( private val leading: List[T], private val trailing: List[T]) { def head = leading.head def tail = new Queue(leading.tail, trailing) def append(x: T) = new Queue(leading, x :: trailing)}
elems == leading ::: trailing.reverse
Represent Queue with Two Lists
![Page 49: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/49.jpg)
class Queue[T]( private val leading: List[T], private val trailing: List[T]) { def head = leading.head def tail = new Queue(leading.tail, trailing) def append(x: T) = new Queue(leading, x :: trailing)}
elems == leading ::: trailing.reverse
but what if leading.isEmpty?
Represent Queue with Two Lists
![Page 50: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/50.jpg)
Mirroring
class Queue[T]( private val leading: List[T], private val trailing: List[T]) { private def mirror = if (leading.isEmpty) new Queue(trailing.reverse, Nil) else this def head = mirror.leading.head def tail = { val q = mirror new Queue(q.leading.tail, q.trailing) } def append(x: T) = new Queue(leading, x :: trailing)}
![Page 51: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/51.jpg)
Mirroring
class Queue[T]( private val leading: List[T], private val trailing: List[T]) { private def mirror = if (leading.isEmpty) new Queue(trailing.reverse, Nil) else this def head = mirror.leading.head def tail = { val q = mirror new 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
![Page 52: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/52.jpg)
Mirroring
class Queue[T]( private val leading: List[T], private val trailing: List[T]) { private def mirror = if (leading.isEmpty) new Queue(trailing.reverse, Nil) else this def head = mirror.leading.head def tail = { val q = mirror new 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
implementation is exposed!
![Page 53: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/53.jpg)
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 parameters
public auxiliary constructors
hide implementation details from clients
Private Constructors
![Page 54: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/54.jpg)
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 implementation details from clients
factory method
private parameters
![Page 55: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/55.jpg)
trait Queue[T] { def head: T def 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 this def head: T = mirror.leading.head def tail: QueueImpl[T] = { val q = mirror new QueueImpl(q.leading.tail, q.trailing) } def append(x: T) = new QueueImpl(leading, x :: trailing) }
}
hide implementation details from clients
![Page 56: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/56.jpg)
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])Unit
Queue is a trait, not a typeQueue is a type constructor or generic trait
Queue[String] is a (specific) type
Generic Traits
![Page 57: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/57.jpg)
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 T
trait Queue[+T] { ... }
val q: Queue[AnyRef] = Queue[String](“a”)
If answer is no: Queue is contravariant in T
trait Queue[-T] { ... }
val q: Queue[String] = Queue[AnyRef]() default: nonvariant
Subtyping & Variance Annotations
![Page 58: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/58.jpg)
class Cell[+T](init: T) { private[this] var current = init def get = current def set(x: T) { current = x }}
val c1 = new Cell[String]("abc")val c2: Cell[Any] = c1c2.set(1)val s: String = c1.get
Covariance and Mutable Classes
![Page 59: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/59.jpg)
class Cell[+T](init: T) { private[this] var current = init def get = current def set(x: T) { current = x }}
val c1 = new Cell[String]("abc")val c2: Cell[Any] = c1c2.set(1)val s: String = c1.get
Cell.scala:7: error: covariant type T occurs incontravariant position in type T of value xdef set(x: T) = current = x
Covariance and Mutable Classes
![Page 60: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/60.jpg)
package society { package professional { class Executive { private[professional] var workDetails = null private[society] var friends = null private[this] var secrets = null
def help(another : Executive) { println(another.workDetails) println(another.secrets) //ERROR } } }}
Source: http://www.tutorialspoint.com/scala/scala_access_modifiers.htm
Scope of Protection of Access Modifiers
A 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.
![Page 61: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/61.jpg)
// this is JavaString[] a1 = { "abc" };Object[] a2 = a1;a2[0] = new Integer(17);String s = a1[0];
no compile-time error
Variance and Arrays
![Page 62: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/62.jpg)
// 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 error
Variance and Arrays
![Page 63: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/63.jpg)
// 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 error
motivation: generic treatment of arrays:
void sort(Object[] a, Comparator cmp) { ... }
Variance and Arrays
![Page 64: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/64.jpg)
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
![Page 65: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/65.jpg)
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")
Checking Variance Annotations
![Page 66: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/66.jpg)
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) = ˆ
Checking Variance Annotations
![Page 67: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/67.jpg)
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 Fruit
scala> val qa = Queue(new Apple)scala> val qb = qa.append(new Orange)qb: Queue[Fruit] = ...
U >: T == U is a supertype of T
Lower Bounds
![Page 68: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/68.jpg)
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 :: leading trailing = 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
![Page 69: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/69.jpg)
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, _) => ys case (_, Nil) => xs case (x :: xs1, y :: ys1) => if (x < y) x :: merge(xs1, ys) else y :: merge(xs, ys1) } val n = xs.length / 2 if (n == 0) xs else { val (ys, zs) = xs splitAt n merge(orderedMergeSort(ys), orderedMergeSort(zs)) }}
Upperbounds
![Page 70: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/70.jpg)
Information hiding
• private constructors
• factory methods
• object private members
Type variance
• subtyping of generic types
• covariant, contravariant variance annotations
• lower bounds, upper bounds
Type Parameterization Summary
![Page 71: TI1220 Lecture 8: Traits & Type Parameterization](https://reader033.vdocument.in/reader033/viewer/2022060110/5559e9d0d8b42a34498b5163/html5/thumbnails/71.jpg)
Reading & Programming in Week 6
Reading
Scala Chapter 12: Traits
Scala Chapter 19: Type Parameterization
Week 9: Parsers and Interpreters
WebLab: Graded Assignment 2: (deadline 14 May 2013, 23:59)