% CSE 130: Spring 2012
% Subtyping 
% Ranjit Jhala, UC San Diego 

## News

>- PA 6 is out, due Fri 6/1

>- PA 7 is Prolog

## Brief Digression Into PA6

> - Decorators e.g. [Profiling](lec-subtyping/Decorators.scala)

> - ScalaCheck e.g. [BST Bug](lec-subtyping/Bst.scala)

> - Case Classes e.g. [`IntList`](lec-subtyping/IntList.scala)

## Today's Plan: Subtyping

### When **is** an object **like** another?

> - When does one object **behave like** another?

> - When can we **substitute** one widget with another?

### Example

> - What kinds of `Point` objects can we send to `screenSaver`?

> - What **is a** `Point`?

### Essential for **safe code reuse**

## Recap: Objects and Types

### Objects

> - Maps from **names** to **properties** 

> - Properties = Data + Functions (+ Objects)

## Recap: Types

- Short descriptions of Objects

- Maps from **names** to **types**

### Description of object properties 

- The actions one can perform on object

- Field and Methods and their respective types

## Recap: Types

- Short descriptions of Objects

- Maps from **names** to **types**

Example: `ticker` 

~~~~~{.scala}
{ def next(): Any
  def hasNext: Boolean }
~~~~~

Example: `Int`

~~~~~{.scala}
{ def .+(other: Int) : Int // add       method
  def .-(other: Int) : Int // subtract  method
  ...//etc }
~~~~~

## Recap: Types

- Short descriptions of Objects

- Maps from **names** to **types**

Example: `Point`

~~~~~{.scala}
class Point {
  val name : String                 // immutable field
  var x    : Int                    // mutable field
  var y    : Int                    // mutable field
  def render(g: Graphics): Unit     // method 
  def move(d: Dimension, del: Int)  // method
} 
~~~~~

## Recall ScreenSaver

~~~~~{.scala}
def screenSaver(p: Point) {

  // Only uses properties described in Point 

}
~~~~~

### A Type is a **Contract**

> - Method (`ScreenSaver`) **promises** to only use attributes of `Point`

> - Caller (`main`) **promises** to only send `Point` values

> - Easy for compiler to verify

> - But **what** exactly **is a** `Point` value?

## What is a `Point` ?

What objects can we really call `ScreenSaver` with?

> - Only those created by `new Point(...)` ?

> - That seems too restrictive. What about ?
>     - `Dot`
>     - `ColorDot`
>     - `Box`
>     - `ColorBox`

> - Why are those **also** allowed?

## Subtyping

What objects can we really call `ScreenSaver` with?

> - Intuitively, **any** object with `Point` attributes 

> - If object has **more** attributes, no problem!

> - This notion is called **subtyping**
>     - `Dot`
>     - `ColorDot`
>     - `Box`
>     - `ColorBox` 
>     - .. are **subtypes** of `Point`

### Notation: `S <: T` means type `S` is a subtype of type `T`


# If `S<:T` then we may replace `T` objects with `S` objects

## Subtype Polymorphism

> - If `S <: T` then `T` objects can be **replaced with** `S` objects

> - If a function expects `T` objects, it can be called with `S` objects


## Subtype Polymorphism

If `S <: T` then `T` objects can be **replaced with** `S` objects

- `Dot      <: Point`
- `ColorDot <: Dot <: Point`
- `Box      <: Dot <: Point`
- `ColorBox <: Dot <: Point`

~~~~~{.scala}
def screen(p: Point) {
  // Only uses properties described in Point 
}
~~~~~

So `screen` can be called with `Dot`, `ColorDot`, `Box`, `ColorBox` 

# Sounds great in theory, but when is `S <: T`

## Sounds great in theory, but when is `S <: T`

### Intuition

When every object of type `S` **"IS A"** object of type `T`

> - When `S` *has all attributes* of `T` 

> - (... and maybe extra ones.)

## Sounds great in theory, but when is `S <: T`

### Example: `S <: T` if `S` has all attributes of `T`

~~~~~{.scala}
class ColorDot {
  val color : Color  // Extra Field
  val name  : String
  var x     : Int
  var y     : Int
  def render(g: Graphics): Unit
  def move(d: Dimension, delta: Int) 
}
~~~~~

**is a** (subtype of)

~~~~~{.scala}
class Dot {
  val name : String
  var x    : Int
  var y    : Int
  def render(g: Graphics): Unit
  def move(d: Dimension, delta: Int) 
}
~~~~~


## Subtyping Rule `S <: T` 

**Width Subtyping:** when `S` has **more** attributes than `T`

### If

> - `S` = `{ val f0: S0;  val f1: S1; ... ; val fn: Sn }`

> - `T` = `{              val f1: S1; ... ; val fn: Sn }`

### Then

> - `S <: T`






## Hold on a minute!

### We know 

> - `Dot <: Point`     (**extra field:** `name`)

> - `ColorDot <: Dot`  (**extra field:** `color`)

### But how do we get

> - `ColorDot <: Point` ?


## Subtyping Rule `S <: T` 

**Transitive Subtyping**: The **Is-A** relation is transitive

### If

> - `S <: Thing`  

> - `Thing <: T`

### Then

> - `S <: T`

# But intuition can be a tricky thing...

## Given types `S` and `T`, how can we know if `S <: T` ?

We know `ColorDot <: Dot`. What about `ColorLine` and `Line`?

~~~~~{.scala}
class Line {
  val p1: Dot
  val p2: Dot
}
~~~~~

and

~~~~~{.scala}
class ColorLine {
  val p1: ColorDot
  val p2: ColorDot
}
~~~~~

## QUIZ: How can we know if `S <: T` ?

We know `ColorDot <: Dot`. What about `ColorLine` and `Line`?

~~~~~{.scala}
class Line {
  val p1: Dot
  val p2: Dot
}

class ColorLine {
  val p1: ColorDot
  val p2: ColorDot
}
~~~~~

For **any** function `def foo(l: Line)`, 
is it OK to call `foo` with a `ColorLine` ?

**A.** Hells, Yes!

**B.** OMG, NO!

## Given types `S` and `T`, how can we know if `S <: T` ?

We know `ColorDot <: Dot`. 

What about `ColorLine` and `Line`?

For **any** function 

~~~~~{.scala}
def foo(l: Line)
~~~~~

Is it OK to call `foo` with a `ColorLine` ? **Yes**

> - Only thing `foo` can do is **use** `p1` and `p2` as `Dot`...

> - A `ColorLine` has those fields **with properties of** `ColorDot`

> - But a `ColorDot` **is a** `Dot`

> - Hence, we **can** call `foo` with `ColorLine` objects.


## Subtyping Rule `S <: T` 

**Depth Subtyping:** when `S` fields **are subtypes of** `T` fields

### If

> - `S` = `{ val f1: S1; ... ; val fn: Sn }`

> - `T` = `{ val f1: T1; ... ; val fn: Tn }`

> - `S1 <: T1` and `S2 <: T2` and ...  `Sn <: Tn`

### Then

> - `S <: T`

# Digression: Subtyping on Function Types ...

## Given types `S` and `T`, how can we know if `S <: T` ?

### Subtyping Function Types

> - First, we look at outputs (with the *same input* type)
>       - When is `(In => S) <: (In => T)`? 

> - Next, lets look at inputs (with the *same output* type)
>       - When is `(S => Out) <: (T => Out)`? 

> - Finally, we can combine the two...
>       - When is `(S1 => S2) <: (T1 => T2)`? 





## Given types `S` and `T`, how can we know if `S <: T` ?

### Subtyping Function Types

- **First, we look at outputs (with the same input type)**
      - **When is `(In => S) <: (In => T)`?**

- Next, lets look at inputs (with the *same output* type)
      - When is `(S => Out) <: (T => Out)`? 

- Finally, we can combine the two...
      - When is `(S1 => S2) <: (T1 => T2)`? 





## Output Subtyping: When is `In=>S <: In=>T` ? 

### Is `() => ColorDot <: () => Dot` ?

Suppose I have a method whose **input** has type `() => Dot` 

~~~~~{.scala}
def screenSaver(f:() => Dot): Unit
~~~~~

Also, suppose I have a function that returns `ColorDot <: Dot`

~~~~~{.scala}
val getColorDot: () => ColorDot
~~~~~

### QUIZ: Is it safe to do `screenSaver(getColorDot)` ?

**A.** Yes

**B.** No

## Output Subtyping: When is `In=>S <: In=>T` ? 

### Is `() => ColorDot <: () => Dot` ?

Suppose I have a method whose **input** has type `() => Dot` 

~~~~~{.scala}
def screenSaver(f:() => Dot): Unit
~~~~~

Also, suppose I have a function that returns `ColorDot <: Dot`

~~~~~{.scala}
val getColorDot: () => ColorDot
~~~~~

### QUIZ: Is it safe to do `screenSaver(getColorDot)` ? **YES**

> - Only thing `screenSaver` can do is call `f` to get a `Dot` ...
> - ... on which it operates using `Dot`s properties

> - When `screenSaver` calls `getColorDot` it gets a `ColorDot` ...
> - ... which **is a** `Dot` (has all of `Dot`s properties) ...

## Subtyping Rule `In => S <: In => T` 

### Function Subtyping

Can substitute/use a function with another that **produces fewer outputs** ...

### If

> - `S <: T`

### Then

> - `In => S <:  In => T`

### Example

- As `ColorDot <: Dot` 
- We have `() => ColorDot  <:  () => Dot`


## Given types `S` and `T`, how can we know if `S <: T` ?

### Subtyping Function Types

- First, we look at outputs (with the same input type)
      - `(In => S) <: (In => T)`?
      - If `S <: T`  

- **Next, lets look at inputs (with the *same output* type)**
      - **When is `(S => Out) <: (T => Out)`?**

- Finally, we can combine the two...
      - When is `(S1 => S2) <: (T1 => T2)`? 




## Input Subtyping: When is `S=>Out <: T=>Out` ?

### Is `ColorDot=>Graphic <: Dot=>Graphic` ?

If I have a function whose **input** must be `Dot => Graphic`

~~~~~{.scala}
def plotGraphic(x: Dot => Graphic): Unit
~~~~~

and a function from `ColorDot` to `Graphic`

~~~~~{.scala}
val cd2g: ColorDot => Graphic
~~~~~

### QUIZ: Is it safe to do `plotGraphic(cd2g)` ?

**A.** Yes

**B.** No

## Input Subtyping: When is `S=>Out <: T=>Out` ?

### Is `ColorDot=>Graphic <: Dot=>Graphic` ?

~~~~~{.scala}
def plotGraphic(f: Dot => Graphic) {
  val d = new Dot(0, 0) // not ColorDot
  plot(f(d))    
}

def cd2g(cd: ColorDot) = { 
  val c = cd.color
  setColor(cd.color)
  fillColorOval()
} 
~~~~~

What happens if we do ...

~~~~~{.scala}
plotGraphic(cd2g)
~~~~~

?

## Input Subtyping: When is `S=>Out <: T=>Out` ?

### Is `ColorDot=>Graphic <: Dot=>Graphic` ?

~~~~~{.scala}
def plotGraphic(f: Dot => Graphic) {
  val d = new Dot(0, 0) // not ColorDot
  plot(f(d))            // cd2g(d) crashes! 
}

def cd2g(cd: ColorDot) = { 
  val c = cd.color
  setColor(cd.color)
  fillColorOval()
} 

plotGraphic(cd2g)
~~~~~

### **Yikes!** the call `f(d)` in `plotGraphic` crashes!

> - As `cd2g(new Dot(0, 0))` tries to access `.color` field ...
> - ... which does not exist in `Dot`!

## Input Subtyping: When is `S=>Out <: T=>Out` ?

### Is `ColorDot=>Graphic <: Dot=>Graphic` ?

> - **B.** No!

> - Cannot **use** a `ColorDot=>Graphic` instead of `Dot=>Graphic`

> - Cannot **substitute** a `ColorDot=>Graphic` in place of `Dot=>Graphic`

> - !!!

## Input Subtyping: When is `S=>Out <: T=>Out` ?

### How about `Dot=>Graphic <: ColorDot=>Graphic` ?



## Input Subtyping: When is `S=>Out <: T=>Out` ?

### How about `Dot=>Graphic <: ColorDot=>Graphic` ?

Suppose we have:

~~~~~{.scala}
def plotColorGraphic(f: ColorDot => Graphic)

def d2g(d: Dot)
~~~~~

Would `plotGraphic(cd2g)` cause any problems?

> - **No!** **Non!** **Nein!** **Nada!** **Nahin!**

> - `plotColorGraphic` will only call `f` with `ColorDot` values ...

> - ... all of which are `Dot` values ...

> - ... so `d2g` will have no problem handling them! 

## Input Subtyping: When is `S=>Out <: T=>Out` ?

### How about `Dot=>Graphic <: ColorDot=>Graphic` ?

Suppose we have:

~~~~~{.scala}
def plotColorGraphic(f: ColorDot => Graphic)

def d2g(d: Dot)
~~~~~

Would `plotGraphic(cd2g)` cause any problems?

**Safe** to use a function that **accepts more inputs**

## Subtyping Rule `T => Out <:  T => Out` 

### Function Subtyping

Can substitute/use a function with another that **accepts more inputs** ...

### If

> - `T <: S`

### Then

> - `S => Out <:  T => Out`

### Example

- As `ColorDot <: Dot` 

- We have `Dot => Graphic  <:  ColorDot => Graphic`


## Function Subtyping in Pictures

<img src="lec-subtyping/out1.png" width=600 align="middle"/> 

## Function Subtyping in Pictures

<img src="lec-subtyping/out2.png" width=600 align="middle"/> 


## Function Subtyping in Pictures

<img src="lec-subtyping/out3.png" width=800 align="middle"/> 

## Function Subtyping in Pictures

<img src="lec-subtyping/out4.png" width=800 align="middle"/> 

## Given types `S` and `T`, how can we know if `S <: T` ?

### Subtyping Function Types

- First, we look at outputs (with the same input type)
      - `(In => S) <: (In => T)`?
      - If: `S <: T`  

- Next, lets look at inputs (with the *same output* type)
      - When is `(S => Out) <: (T => Out)`?
      - If: `T <: S`  

- **Finally, we can combine the two...**
      - **`(In1 => Out1) <: (In2 => Out2)` ?**

 
## QUIZ: Function Subtyping

You tell me!

`In1 => Out1    <:   In2 => Out2`

If:

**A.** `In1 <: In2` and `Out1 <: Out2`

**B.** `In2 <: In1` and `Out1 <: Out2`

**C.** `In1 <: In2` and `Out2 <: Out1`

**D.** `In2 <: In1` and `Out2 <: Out1`


## Function Subtyping

You tell me!

`In1 => Out1   <:  In2 => Out2`

We can use `f1: In1 => Out1` in place of  `f2: In2 => Out2`

If:

> - `f1` **accepts more inputs**
>     - `In2 <: In1`

> - `f2` **produces fewer outputs**
>     - `Out1 <: Out2`

> - Solution: **B.** `In2 <: In1` and `Out1 <: Out2`

## Given types `S` and `T`, how can we know if `S <: T` ?

### Subtyping Function Types

If 

- `In2 <: In1`
- `Out1 <: Out2`

Then

- `In1 => Out1   <:  In2 => Out2`

## Given types `S` and `T`, how can we know if `S <: T` ?

### Subtyping Function Types

If 

- `In2 <: In1`
- `Out1 <: Out2`

Then

- `In1 => Out1   <:  In2 => Out2`

### Jargon

> - **Contravariant** on input type
> - **Covariant**  on output type

# End Digression: Back To Objects/Classes...(but don't forget functions!)

## QUIZ: How can we know if `S <: T` ?

We know `ColorDot <: Dot`. How about these two (with **getter** methods)

~~~~~{.scala}
class Line {
  def getP1(): Dot
  def getP2(): Dot
}
~~~~~

and

~~~~~{.scala}
class ColorLine {
  def getP1(): ColorDot
  def getP2(): ColorDot
}
~~~~~

Is `ColorLine <: Line` ? (Is it OK to call `foo` with a `ColorLine`?)

**A.** Yes

**B.** No

## Given types `S` and `T`, how can we know if `S <: T` ?

We know `ColorDot <: Dot`. How about these two (with **getter** methods)

~~~~~{.scala}
class Line {
  def getP1(): Dot
  def getP2(): Dot
}
~~~~~

and

~~~~~{.scala}
class ColorLine {
  def getP1(): ColorDot
  def getP2(): ColorDot
}
~~~~~

**Yes** we can call `foo` with a `ColorLine`

> - `foo` can only **get** and **use** `p1` and `p2` as `Dot`...
> - A `ColorLine` has those fields **with properties of** `ColorDot`
> - But a `ColorDot` **is a** `Dot`
> - Hence, we **can** call `foo` with `ColorLine` objects.

## Given types `S` and `T`, how can we know if `S <: T` ?

We know `ColorDot <: Dot`. How about these two (with **getter** methods)

~~~~~{.scala}
class Line {
  def getP1: () => Dot
  def getP2: () => Dot
}

class ColorLine {
  def getP1: () => ColorDot
  def getP2: () => ColorDot
}
~~~~~

Lets use the **rules** to derive `ColorLine <: Line` ?

> - By **Function Subtyping** : `() => ColorDot  <:  () => Dot` 
> - Hence, `ColorLine.getP1 <: Line.getP1` 
> - And, `ColorLine.getP2 <: Line.getP2`
> - So, by **Depth Subtyping**: `ColorLine <: Line`


## Given types `S` and `T`, how can we know if `S <: T` ?

We know `ColorDot <: Dot`. How about these two (with **setter** methods)

~~~~~{.scala}
class Line { 
  // other fields from before ...
  def setP1(p: Dot): Unit
  def setP2(p: Dot): Unit
}

class ColorLine {
  // other fields from before ...
  def setP1(p: ColorDot) : Unit
  def setP2(p: ColorDot) : Unit
}
~~~~~

### Is `ColorLine <: Line` ?

For **any** function `foo`, can we call `foo(new ColorLine(...))` ?

~~~~~{.scala}
def foo(l: Line) {...} 
~~~~~


## Given types `S` and `T`, how can we know if `S <: T` ?

OK to call `foo` with a `ColorLine`? (for **any** `def foo(l: Line)`)

~~~~~{.scala}
class Line      { def setP1(p: Dot): Unit }

class ColorLine { def setP1(p: ColorDot) : Unit }
~~~~~


Suppose that `ColorLine <: Line` ?

Consider the following `foo`

~~~~~{.scala}
def foo(l: Line) { l.setP1(new Dot(0, 0)) }
~~~~~

Now, all hell breaks loose:

~~~~~{.scala}
val cl     = new ColorLine
foo(cl)                     // Typechecks 
val color1 = l.getP1.color  // Runtime Error! 
~~~~~

# But the rules would have told us this!

## Given types `S` and `T`, how can we know if `S <: T` ?

If `ColorDot <: Dot` then is `ColorLine <: Line` ?

~~~~~{.scala}
class Line { 
  // from before ...
  def setP1: Dot => Unit
  def setP2: Dot => Unit
}

class ColorLine {
  // from before ...
  def setP1: ColorDot => Unit
  def setP2: ColorDot => Unit
}
~~~~~

### Fields are Not Subtypes

> - `ColorLine.setP1` **not a subtype of** `Line.setP1` ...
> - ... accepts **fewer** inputs


## Recap: Subtyping = Is an object like another?

Can one widget be **safely substituted** with another?

### Subtyping Relation `S <: T`

Says when a value of type `S` **is a** value of type `T`

> - **Width Subtyping:** when `S` has **more** attributes than `T`

> - **Depth Subtyping:** when `S` fields **are subtypes of** `T` fields

> - **Transitive Subtyping**: The **"Is-A"** relation is transitive

> - **Function Subtyping** when `S` accepts **more inputs**, produces **fewer outputs**

# Recap: Subtyping Enables Polymorphism and Reuse

## Recap: Subtype Polymorphism 

If `S <: T` then `T` objects can be **replaced with** `S` objects

- `Dot      <: Point`
- `ColorDot <: Dot <: Point`
- `Box      <: Dot <: Point`
- `ColorBox <: Dot <: Point`

~~~~~{.scala}
def screen(p: Point) {
  // Only uses properties described in Point 
}
~~~~~

So `screen` can be called with `Dot`, `ColorDot`, `Box`, `ColorBox` 
