- Fill this out!
- So far, <30% submitted.

- CTD does research about using clickers in the classroom.
- Fill this out!
- If you do, you get
30 EXTRA CREDIT HW POINTS.- (I won't get answers until
aftergrades are submitted.)

- Tuesday, March 18, 11:30am -- 2:30pm in CENTR 214 (this room!)

- OCaml: ~11 lectures and 4 homeworks
- Scala: ~6 lectures and 2 homeworks

- The exam will reflect this difference in time spent.

- Be generally comfortable with the Scala material and assignments...
- But
no needto agonize over details of Subtyping and Generics.

- Will be posted on webpage

- Saturday, March 15, 6pm -- 8pm in CSE Building Room 1202
- Come prepared with questions!

SubtypePolymorphism ("Is-A" style; classic OO)

ParametricPolymorphism ("Type Variables"; ML style)

- Scala combines them in interesting ways.

- Functions
- Classes/Traits

Implicitlyretrofitting behavior to existing types.- Sadly, we won't have time to cover this.
- But it's awesome, so you should read about it for fun!

Unlike OCaml, you have to **write down** the type variables:

```
/* OCaml: let id x = x */
scala> def id[A](x:A) = x
id: [A](x: A)A
/* OCaml: let swap p = (snd p, fst p) */
scala> def swap[A,B](p: (A,B)) = (p._2, p._1)
swap: [A, B](p: (A, B))(B, A)
```

- Recall:
`'a -> 'a`

in OCaml really meant "`forall 'a. 'a -> 'a`

"

- In Scala, you have to write the "forall" part with
`[...]`

At function call, can **explicitly** instantiate the type parameters:

```
scala> swap[Int, Boolean](1, true)
res10: (Boolean, Int) = (true,1)
```

But often, local type inference can **implicitly** instantiate them:

```
scala> swap(1, true)
res11: (Boolean, Int) = (true,1)
```

Recall the **type ascription** expression from last time.

```
scala> List()
res17: List[Nothing] = List()
scala> List(): List[Int]
res18: List[Int] = List()
scala> List(): List[Boolean]
res19: List[Boolean] = List()
scala> List(): List[List[Int]]
res20: List[List[Int]] = List()
```

Recall the **type ascription** expression from last time.

```
scala> Nil
res23: scala.collection.immutable.Nil.type = List()
scala> Nil: List[Int]
res24: List[Int] = List()
scala> Nil: List[Boolean]
res25: List[Boolean] = List()
scala> Nil: List[List[Int]]
res26: List[List[Int]] = List()
```

Wait, there are **two** ways to describe the empty list?

```
scala> Nil: List[Int]
res24: List[Int] = List()
scala> List(): List[Int]
res18: List[Int] = List()
scala> Nil == List()
res32: Boolean = true
```

**Datatypes** in OCaml were awesome.

`# type t = A | B ;;`

- Compiler figured out
inexhaustiveandredundantpatterns:

```
# let foo x = match x with A -> () ;;
Warning: this pattern-matching is not exhaustive.
foo : t -> unit
# let bar x = match x with A -> () | B -> () | B -> () ;;
Warning: this match case is unused.
bar : t -> unit
```

`# type t = A | B ;;`

- Easy to define
new operation(`foo`

,`bar`

,`baz`

) for every`t`

-typed value.

```
class t
class A() extends t
class B() extends t
```

- Easy to define
new kind(sub-class`A`

,`B`

,`C`

) of`t`

-typed value.

- Can we have the best of both?

A mix of classes and datatypes...

```
class t
case class A() extends t
case class B() extends t
```

... that enables **pattern matching**!

```
def foo(x: t) = x match {
case A() => println("A")
case B() => println("B")
}
```

```
class t
case class A() extends t
def bar(x: t) = x match {
case A() => println("A")
case A() => println("A")
}
```

What is the result of evaluating `bar`

?

**A:** Type Error

**B:** `t -> Unit`

**C:** `t -> Unit`

with a warning

```
class t
case class A() extends t
def bar(x: t) = x match {
case A() => println("A")
case A() => println("A")
}
```

- Scala has no problem detecting
redundantcases.

C:`t -> Unit`

with a warning

```
class t
case class A() extends t
case class B() extends t
def baz(x: t) = x match {
case A() => println("A")
}
```

What is the result of evaluating `bar`

?

**A:** Type Error

**B:** `t -> Unit`

**C:** `t -> Unit`

with a warning

```
class t
case class A() extends t
case class B() extends t
def baz(x: t) = x match {
case A() => println("A")
}
```

B:`t -> Unit`

(withnowarning)

- Why can't Scala figure out
inexhaustivepattern match?

- Because
subclassescan be defined anywhere later!

If a (regular or case) class is marked as **sealed**...

```
sealed class t
case class A() extends t
case class B() extends t
```

- Then
all subclassesmust appear in the same file.- They may not appear anywhere else.

- So the following leads to
compile-timewarning:

```
def baz(x: t) = x match {
case A() => println("A")
}
```

```
(* ML *)
let rec length xs = match xs with
| [] -> 0
| _::t -> 1 + length t
```

```
/* Scala */
def length[A](xs: List[A]): Int =
xs match {
case Nil => 0
case (_ :: t) => 1 + length(t)
}
```

```
(* ML *)
let rec map f xs = match xs with
| [] -> []
| x::t -> (f x) :: map (f, t)
```

```
/* Scala */
def map[A, B](f: A => B)(xs: List[A]): List[B] =
xs match {
case Nil => List()
case (_ :: t) => (f(x))::(map(f)(rest))
}
```

```
// Subtype Polymorphism
def headAny(xs: List[Any]): Any =
xs match {
case h :: _ => h
case _ => sys.error("head of empty list")
}
// Parametric Polymorphism
def headPoly[A](xs: List[A]): A =
xs match {
case h :: _ => h
case _ => sys.error("head of empty list")
}
```

- They seem to behave the same, but types are different...

```
// Subtype Polymorphism
def headAny(xs: List[Any]): Any = ...
// Parametric Polymorphism
def headPoly[A](xs: List[A]): A = ...
```

- They can both be called with
anytype of list...

- But the return type of
`headAny`

isvery imprecise.

- Whereas the return type of
`headPoly`

isvery precise.

```
// Subtype Polymorphism
def headAny(xs: List[Any]): Any = ...
// Parametric Polymorphism
def headPoly[A](xs: List[A]): A = ...
scala> val ns = List(1,2,3)
ns: List[Int] = List(1, 2, 3)
scala> val (i, j) = (headAny(ns), headPoly(ns))
i: Any = 1
j: Int = 1
```

- We've already hinted at this with
`List[A]`

.

- Now let's see how to
definea class with type variables.

- Our running example will be polymorphic
sets(a.k.a"bags").- UnorderedBag.scala

```
sealed abstract class Bag[A]
case class Empty[A]() extends Bag[A]
case class Plus[A](elt: A, rest: Bag[A]) extends Bag[A]
```

- Very similar to what you might write in OCaml:

`type 'a bag = Empty | Plus of ('a * 'a bag)`

```
sealed abstract class Bag[A]
case class Empty[A]() extends Bag[A]
case class Plus[A](elt: A, rest: Bag[A]) extends Bag[A]
```

**Case Classes** are Just Vanilla Classes...

- But no need for pesky
`new`

to create instances

- But also support
pattern matching

```
sealed abstract class Bag[A]
case class Empty[A]() extends Bag[A]
case class Plus[A](elt: A, rest: Bag[A]) extends Bag[A]
```

We can fill in various methods...

```
sealed abstract class Bag[A] {
...
def size : Int =
this match {
case Empty() => 0
case Plus(_, rest) => 1 + rest.size
}
...
}
```

- The
`this`

expression denotes thereceiverbag.

We can fill in various methods...

```
sealed abstract class Bag[A] {
// ...
def contains(x: A) : Boolean = {
this match {
case Empty() => false
case Plus(e, _) if (x == e) => true
case Plus(_, rest) => rest.contains(x)
}
}
// ...
}
```

Type parameter`A`

isin scopein entire class definition.

We can fill in various methods...

```
sealed abstract class Bag[A] {
// ...
def add(x: A) : Bag[A] = {
if (this.contains(x)) this else { Plus(x, this) }
}
// ...
}
```

- A brand new,
immutable`Bag`

returned as output.

We can fill in various methods...

```
sealed abstract class Bag[A] {
// ...
def gimme: Option[A] =
this match {
case Plus(x, rest) => Some(x)
case _ => None
}
// ...
}
```

- Element is
not removedfrom`this`

bag.

- Functions
- Classes/Traits

+ Parametric Polymorphism

`res`

?```
def findMin[A](cur: A, xs: List[A]): A = xs match {
case Nil => cur
case h::t if (h < cur) => findMin(h, t)
case _::t => findMin(cur, t)
}
val res = findMin(1000, List(20, 4, 1, 6))
```

**A.** Type Error in `findMin(1000, ...)`

**B.** Type Error in definition of `findMin`

**C.** Type Error in `List(20,4,1,6)`

**D.** `1`

**E.** `20`

`res`

?```
def findMin[A](cur: A, xs: List[A]): A = xs match {
case Nil => cur
case h::t if (h < cur) => findMin(h, t)
case _::t => findMin(cur, t)
}
val res = findMin(1000, List(20, 4, 1, 6))
```

B.Type Error in definition of`findMin`

```
error: value < is not a member of type parameter A
case h::t if (h < cur) => findMin(h, t)
^
```

support comparison...

```
trait Ord[A] {
def cmp(that: A): Int // Must Be Implemented ...
// ... Automatically derived from cmp !
def ===(that: A): Boolean = (this cmp that) == 0
def <(that: A): Boolean = (this cmp that) < 0
def >(that: A): Boolean = (this cmp that) > 0
def <=(that: A): Boolean = (this cmp that) <= 0
def >=(that: A): Boolean = (this cmp that) <= 0
}
```

- From one required method, we get a bunch of methods
for free!- (Similar to
type classesin Haskell.)

```
def findMin[???](cur: ???, xs: List[???]): ??? =
xs match {
case Nil => cur
case h::t if (h < cur) => findMin(h, t)
case _::t => findMin(cur, t)
}
```

- We want to say
any type`A`

... (parametric polymorphism)

- That is a
subtypeof`Ord`

. (subtyping)

- Combine both kinds of polymorphism with
bounded quantification.`[A <: Ord[A]]`

```
def findMin[A <: Ord[A]](cur: A, xs: List[A]): A =
xs match {
case Nil => cur
case h::t if (h < cur) => findMin(h, t)
case _::t => findMin(cur, t)
}
```

- We'll come back to this example in a bit...

- But first, let's make an
orderedversion of`Bag`

.

`Bag`

is a pretty lame data structure

`contains`

,`add`

, etc.- Must walk over
entirebag to determine if elements are present.

- Let us arrange the elements in
increasingorder ...- ... can tell if an element is
absentwhen we find abiggerone.

- Note: this is starting to sound like
`Bst`

in Homework 6...

`Bag`

```
sealed abstract class Bag[A <: Ord[A]] {
// ...
}
```

- For every
`A`

that is asubtypeof`Ord[A]`

(i.e. thatimplements`Ord[A]`

)

- We define the methods of
`Bag[A]`

A *faster* version of `contains`

that does not walk the entire bag.

```
sealed abstract class Bag[A <: Ord[A]] {
// ...
def contains(x: A) : Boolean =
this match {
case Empty() => false
case Plus(e, _) if (x == e) => true
case Plus(e, _) if (x > e) => false
case Plus(_, rest) => rest.contains(x)
}
// ...
}
```

... Assuming that elements are ordered in the first place!

So, we must change the `add`

method to enforce this invariant.

```
sealed abstract class Bag[A <: Ord[A]] {
// ...
def add(x: A) : Bag[A] =
this match {
case Plus(e, es) if (x > e) => Plus(e, es.add(x))
case Plus(e, _) if (x == e) => this
case _ => Plus(x, this)
}
// ...
}
```

The `remove`

method can also be made a bit more efficient.

No need to go to the end:

```
sealed abstract class Bag[A <: Ord[A]] {
// ...
def remove(x: A) : Bag[A] =
this match {
case Plus(e, es) if (x < e) => this
case Empty() => this
case Plus(e, es) if (x == e) => es
case Plus(e, es) => Plus(e, es.remove(x))
}
// ...
}
```

`[A <: T]`

describes

All types`A`

... (parametric polymorphism)

- That are
subtypesof`T`

. (subtyping)

`res`

?```
def findMin[A <: Ord[A]](cur: A, xs: List[A]): A =
xs match {
case Nil => cur
case h::t if (h < cur) => findMin(h, t)
case _::t => findMin(cur, t)
}
val res = findMin(1000, List(20, 4, 1, 6))
```

**A.** Type Error in `findMin(1000, ...)`

**B.** Type Error in definition of `findMin`

**C.** `1`

`res`

?```
def findMin[A <: Ord[A]](cur: A, xs: List[A]): A =
xs match {
case Nil => cur
case h::t if (h < cur) => findMin(h, t)
case _::t => findMin(cur, t)
}
val res = findMin(1000, List(20, 4, 1, 6))
```

- When call instantiates
`A`

with type argument`Int`

,- Scala checks if
`Int`

is a subtype of`Ord[Int]`

.

- But we
just defined`Ord`

...- So of course
`Int`

is not a subtype of`Ord[Int]`

!

`res`

?

A.Type Error in`findMin(1000, ...)`

```
scala> val res = findMin(1000, List(1,2,3))
error: inferred type arguments [Int] do not conform to
method findMin's type parameter bounds
[A <: Ord[A]]
```

- Explicit type argument makes no difference.

```
scala> val res = findMin[Int](1000, List(1,2,3))
error: type arguments [Int] do not conform to
method findMin's type parameter bounds
[A <: Ord[A]]
```

- But, we don't have time to get to them.

- Keep reading the rest of the slides if you're curious!

We have studied many general **themes** in the context of

- (the core of)
**OCaml**and - (a sliver of)
**Scala**

- Expressions are the programs that can be
writtenin a language.

- At run-time, expressions
evaluateeither

- to a finished
value- to a run-time
error- or infinitely
loop.

- The
semanticsof evaluation can be defined

withoutany notion of types (e.g. OCaml or NanoML)witha notion of types (e.g.`instanceOf`

in Scala or Java)

- Types are a
compile-timedescription ofrun-timebehavior.

- Rule out
certain classesof errors...

- But not all. (e.g.
`null`

pointers, infinite loops)

- Preventing larger classes of errors is
active research area.

- Do
nothave to write types everywhere to get benefits of static types.

Globaltype inference in OCaml.

Localtype inference in Scala.

- Verbosity of Java/C# is not a good argument against statically typed languages!

- Easier to
understand, debug, and changeprograms when data cannot be mutated all over the place.

- Mutation is often helpful or necessary, but use it with
discretion.

- Functions are data!

- They can be returned from functions.

- They can be passed to (higher-order) functions as parameters.

- Facilitate
reusable, generic programming patterns.

Remember these powerful **building blocks** when you:

- Learn new languages (Python, JavaScript, Erlang, Haskell, Go, Rust, ...).

- Choose which languages to write your own code.

- Choose how you write code in whatever language you are using.

- Design your own programming languages!

`findMin`

...- Functions
- Classes/Traits

- Retrofitting Functionality with Proxies

```
def findMin[A]
(cur: A, xs: List[A])(proxy: A => Ord[A]): A =
xs match {
case Nil => cur
case h::t if (proxy(h) < cur) => findMin(h, t)
case _::t => findMin(cur, t)
}
```

- Now, the
`Int`

need notitselfimplement`Ord[Int]`

- i.e.
`Int`

need not support comparisons with`Int`

- But some
proxymust be able to do comparisons on its behalf...

- Let's
createsuch a proxy function!

```
def findMin[A](cur: A, xs: List[A])(proxy: A => Ord[A]) =
xs match {
case Nil => cur
case h::t if (proxy(h) < cur) => findMin(h, t)
case _::t => findMin(cur, t)
}
def intProxy(x: Int) = new Ord[Int] {
def cmp(that: Int) : Int = x - that
}
```

- maps
`x: Int`

to an`Ord[Int]`

object supporting comparisons with`x`

```
def findMin[A](cur: A, xs: List[A])(proxy: A => Ord[A]) =
xs match {
case Nil => cur
case h::t if (proxy(h) < cur) => findMin(h, t)(proxy)
case _::t => findMin(cur, t)(proxy)
}
def intProxy(x: Int) = new Ord[Int] {
def cmp(that: Int) : Int = x - that
}
scala> import ProxyDemo._
scala> findMin(1000, List(20, 4, 1, 6))(intProxy)
res1: Int = 1
```

Of course, we can create proxies for other types, too:

```
def stringProxy(x: String) = new Ord[String] {
def cmp(that: String) : Int = x compare that
}
scala> import ProxyDemo._
scala> findMin("zz", List("apple", "chorizo", "adobado"))
(stringProxy)
res1: String = "adobado"
```

- Add functionality to existing types by letting us
view

`Int`

as implementation of`Ord[Int]`

`String`

as implementation of`Ord[String]`

- Proxies
requireus to

- Pass around the relevant proxy functions ...
- Clutter code with ugly conversions ...

Eliminate the Lame

```
// Mark certain function params as implicit
def sayHello(implicit n: String) = println("Hello " + n)
// Mark certain values as implicit
implicit val defaultName = "Ranjit"
```

- Can call the functions in the usual way:

```
scala> sayHello("Roberto")
Hello Roberto
```

```
// Mark certain function params as implicit
def sayHello(implicit n: String) = println("Hello " + n)
// Mark certain values as implicit
implicit val defaultName = "Ranjit"
```

- Can call the functions in the usual way:

```
scala> sayHello("Roberto")
Hello Roberto
```

- Otherwise, Scala
fills in the blanks:

```
scala> sayHello
Hello Ranjit
```

Scala uses types to fill in the blanks.

- When
missinga value of type`T`

- Scala
automaticallysubstitutes implicit`T`

value ...

- ... if such a value
is in scope.

Suppose I wrote a function expecting `String`

inputs

```
scala> def yu(msg: String) = println("Y U NO " + msg)
yu: (msg: String)Unit
```

Naturally, this is fine ...

```
scala> yu("GIVE EASY FINAL")
Y U NO GIVE EASY FINAL
```

... but this throws an error

```
scala> yu(10)
<console>:9: error: type mismatch;
found : Int(10)
required: String
yu(10)
^
```

Suppose I wrote a function expecting `String`

inputs

```
scala> def yu(msg: String) = println("Y U NO " + msg)
yu: (msg: String)Unit
```

But if we add an **implicit conversion**

```
scala> implicit def i2s(i: Int) = i.toString
i2s: (i: Int)java.lang.String
```

Then lo and behold!

```
scala> yu(10)
Y U NO 10
```

`yu(10)`

fixedto`yu(int2String(10))`

- Using the type mismatch and type of
`i2s`

- Proxies
requirewe pass around functions & clutter code...

- Implicits automatically insert proxies where needed!

**Step 1:** Make proxy **parameters** implicit

```
def findMin[A](cur: A, xs: List[A])
(implicit proxy: A => Ord[A]): A =
xs match {
case Nil => cur
case h::t if (proxy(h) < cur) => findMin(h, t)(proxy)
case _::t => findMin(cur, t)(proxy)
}
```

**Step 2:** Remove explicit **uses** of `proxy`

(Scala automatically inserts them!)

```
def findMin[A](cur: A, xs: List[A])
(implicit proxy: A => Ord[A]): A =
xs match {
case Nil => cur
case h::t if (/*proxy*/h < cur) => findMin(h, t)
case _::t => findMin(cur, t)
}
```

**Step 3:** Make proxy functions implicit

```
implicit def intProxy(x: Int) = new Ord[Int] {
def cmp(that: Int) : Int = x - that
}
implicit def stringProxy(x: String) = new Ord[String] {
def cmp(that: String) : Int = x compare that
}
```

Make proxy

**parameters**implicit.Remove explicit

**uses**of`proxy`

. (Scala automatically inserts them!)Make proxy functions implicit.

```
scala> val res = // look ma, no proxies!
findMin(1000, List(10, 2, 30, 14))
res: Int = 2
```

This pattern is so common that it warrants special syntax.

Instead of:

```
def findMin[A](cur: A, xs: List[A])
(implicit proxy: A => Ord[A]): A
```

We can just write the **equivalent**:

`def findMin[A <% Ord[A]](cur: A, xs: List[A]): A`

- Called a
View Bound.`A <:% Ord[A]`

- For any
`A`

with animplicitproxy mapping`A`

to`Ord[A]`

We can now make a real ordered bag

```
sealed abstract class Bag[A <% Ord[A]] {
def contains(x: A) : Boolean = {
this match {
case Empty() => false
case Plus(e, _) if (x == e) => true
case Plus(e, _) if (x > e) => false
case Plus(_, rest) => rest.contains(x)
}
}
// etc.
```

A **companion object** that makes it easy to create `Bag`

s:

```
/* A Companion Object that has various key methods */
object Bag {
def apply[A <% Ord[A]](xs: A*) : Bag[A] = {
val s0 : Bag[A] = Empty()
xs.toList.foldLeft(s0)(_ add _)
}
}
```

**Note:** the view bound (subtyping + parametric) polymorphism on `apply`

We can finally use `Bag`

with existing types!

```
scala> val b0 = Bag(3,1,4,2)
error: No implicit view available from Int => Ord[Int].
val b0 = Bag(3,1,4,2)
^
```

- Eh? Oh! We forgot to put the implicit proxies
in scope...

- Need to import...

```
scala> import OrdInstances._
scala> val b0 = Bag(3,1,2) // Now it can insert intProxy
b0: Bag[Int] = 1,2,3,4 // Note: the Bag is ordered
scala> b0 gimme
res0: Option[Int] = Some(1)
scala> b0 remove 1 gimme
res1: Option[Int] = Some(2)
scala> b0 remove 1 remove 2 gimme
res2: Option[Int] = Some(3)
scala> b0 remove 1 remove 2 remove 3 gimme
res3: Option[Int] = None
```

We can use **any type** for which an implicit proxy is defined:

```
scala> val b1 = Bag("donkey", "monkey", "cat")
b1: Bag[java.lang.String] = cat,donkey,monkey
scala> b1 contains "monkey"
res: Boolean = true
scala> b1 contains "hippo"
res: Boolean = false
scala> val b2 = b1 add "hippo"
b2: Bag[java.lang.String] = cat,donkey,hippo,monkey
scala> b2 contains "hippo"
res: Boolean = true
```

Scala will automatically **generate** new proxies if we ask nicely:

```
implicit def tup2Proxy[A <% Ord[A], B <% Ord[B]](x: (A, B))
= new Ord[(A, B)] {
def cmp(that: (A, B)) : Int = {
val c1 = x._1 cmp that._1
if (c1 != 0) c1 else { x._2 cmp that._2 }
}
}
```

- This says:

Ifyou have (implicit) proxies for type`A`

and type`B`

Thenyou have an (implicit) proxy for type`(A, B)`

And now we can make `Bag`

s of all sorts of pairs (over `Int`

and `String`

)

```
scala> val tb = Bag((3, "cat"), (2, "horse"),
(1, "zebra"), (0, "giraffe"))
tb: Bag[(Int, java.lang.String)] =
(0,giraffe),(1,zebra),(2,horse),(3,cat)
scala> val tb = Bag((2, (1, "cat")), (30, (20, "horse")),
(11, (7, "zebra")))
tb: Bag[(Int, (Int, java.lang.String))] =
(2,(1,cat)),(11,(7,zebra)),(30,(20,horse))
```

Note:Last case is truly bootstrapped. We get nested tuples for free!

Exercise:Add proxy generators for`List`

,`Set`

, and`Map`

**Parametric Polymorphism**("type variables", ML style)`def add[A](x: A): Bag[A]`

**Subtyping + Parametric**Polymorphism`def add[A <: Ord[A]](x: A): Bag[A]`

**Implicitly retrofitting**behavior to existing types`def add[A <% Ord[A]](x: A): Bag[A]`

- Types enable
reusewithout compromisingsafety

How does **cons** work?

```
scala> 1 :: 2 :: 3 :: Nil
res27: List[Int] = List(1, 2, 3)
```

- No big surprise...
`::`

is amethod!

- What is the above expression equivalent to?

- Is it
`1.::(2.::(3.::(Nil)))`

?

Methods that end in `:`

(like cons ) are associated from **right-to-left**.

```
scala> 1.::(2.::(3.::(Nil)))
res33: List[Double] = List(1.0, 2.0, 3.0)
scala> Nil.::(3.).::(2.).::(1.)
res2: List[Double] = List(1.0, 2.0, 3.0)
scala> Nil.::(3).::(2).::(1)
res0: List[Int] = List(1, 2, 3)
```