CS 152 - Lecture 16

Cover page image

Cay S. Horstmann

What Are Types?

Types in Java/Scala

Strong Typing

Static and dynamic typing

Parameterized Types in Scala

Type Bounds

Variance

Immutable List Example

abstract class GList[+T] {
  def isEmpty : Boolean
  def head : T 
  def tail : GList[T]
}

case class GEmpty[T]() extends GList[T] {
  override def isEmpty : Boolean = true
  override def head = error("No head")
  override def tail = error("No tail")
}

case class GNonEmpty[T](hd : T, tl : GList[T]) extends GList[T] {
  override def isEmpty : Boolean = false
  override def head = hd
  override def tail = tl
}

Positional Safety Checks

Lower Bounds

What about Java?

Lab

???

Step 1: Invariance

We'll start with these classes. Add them to a Scala file.

class Person(val name : String) {
  override def toString = getClass.getName + "[name=" + name + "]" 
}

class Student(name : String, val id : Int) extends Person(name) {
  override def toString = super.toString + "[id=" + id + "]" 
}

object Main extends App {
  val harry = new Person("Harry Smith")
  val sally = new Person("Sally Jones")
  val diana = new Student("Diana Lee", 1729)
  val frank = new Student("Frank Miller", 2525)
}
  1. Add a line of code to demonstrate that Student <: Person, that is, a Student object can be converted to the Person type.
  2. Add a line of code to demonstrate that an Array[Student] can not be converted to Array[Person].
  3. What happens if you try List instead of Array? Why?
  4. What happens when you add a Person to a List[Student]? Does it work? If so, what is the type of the result?

Step 2: Co- and Contravariance

  1. Add the generic class
    class MyPair[T](val first: T, val second: T)

    Is MyPair(Student) a subtype of MyPair(Person)? How did you determine the answer? (Note: There is already a Pair[S, T] in Scala.)

  2. What change do you have to make to the MyPair class to fix the issue of the preceding question? (Hint: It's a very small change.)
  3. Add the following method to the MyPair class:
    def sum(f : Function1[T, Int]) = f(first) + f(second)

    Make objects (with explicit types for extra clarity)

    val f : Function1[Student, Int] = { x : Student => x.id }
    val g : Function1[Person, Int] = { x : Person => x.name.length }
    val p : MyPair[Student] = new MyPair(diana, frank) 

    Can you call p.sum(f)? p.sum(g)? If so, what are the results?

  4. It's not surprising that p.sum(f) works. p is a MyPair[Student] and f is a Function1[Student, Int]. But why does p.sum(g) work, even though the types don't match?

Step 3: Type Bounds

  1. Add the following method to the MyPair class:
    def max = if (first < second) second else first

    Why won't the code compile?

  2. How do you fix the MyPair class so that the max function compiles?
  3. Make some sample code to compute new MyPair(17, 29).max. Did it compile? If not, what fix did you need to make?
  4. Now try forming a MyPair of two Person objects. What happens?
  5. How can you fix this?
  6. Now make a MyPair[Student] and weep.