Type Parameterization in Scala

Ruining (Ray) Li
2 min readMay 14, 2021

Information hiding

  1. Private constructors
class Queue[T] private (
private val leading: List[T],
private val trailing: List[T]
)

Plus auxiliary constructor:

def this() = this(Nil, Nil)
def this(elems: T*) = this(elems.toList, Nil)

Or plus factory method:

object Queue {
def apply[T](xs: T*) = new Queue[T](xs.toList, Nil)
}

2. Alternative: private class

  • Only export a trait that reveals the public interface of the class.
trait Queue[T] {
def head: T
def tail: Queue[T]
def enqueue(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 = ......
def head: T = ......
def tail: QueueImpl[T] = ......
def enqueue(x:T) = ......
}

Some definitions

  • Queue above is a generic trait and a type constructor and Queue[String] is a type.
  • If S is a subtype of type T, then should Queue[S] be considered a subtype of Queue[T]? —Yes → Queue is covariant | No → Queue is nonvariant.
  • Generic types have by default nonvariant subtyping.
trait Queue[+T] { ... } // + indicates covariant subtyping
trait Queue[-T] { ... } // - indicates contravariant subtyping

Queue is contravariant means that if T is a subtype of type S, then Queue[S] is a subtype of Queue[T].

Checking variance annotations

Some covariance might lead to runtime error. For example:

class Cell[+T](init: T) {
private var current = init // violates CONDITION
def get = current
def set(x: T) = { current = x }
}
val c1 = new Cell[String]("abc")
val c2: Cell[Any] = c1
c2.set(1)
val s: String = c1.get
class StrangeIntQueue extends Queue[Int] {
override def enqueue(x: Int) = { // violates CONDITION
println(math.sqrt(x))
super.enqueue(x)
}
}
val x: Queue[Any] = new StrangeIntQueue
x.enqueue("abc")

What’s wrong? As soon as a generic parameter type appears as the type of a method parameter [CONDITION], the containing class or trait may not be covariant in that type parameter.

N.B.

  • a reassignable field is treated in Scala as a getter method and a setter method.
  • Object private definitions (which can be accessed only from within the object in which they are defined) are omitted Scala check variance annotations.
// Object private definition
private[this] var leading: List[T]

--

--

Ruining (Ray) Li

From Oxford. Studying Computer Science and on my way to a badass geek.