Scala (3): Type Parameterization

Type

We can define function’s parameter is Int, which means that the input is Int type. In fact, function also can be generic, which can support any types.

trait Cache[K, V] {
  def get(key: K): V
  def put(key: K, value: V)
  def delete(key: K)
}

Also for method it is also can use type parameter.

def remove[K](key: K)

Hide Information

We can hide the primary constructor by adding a private modifier in front of the class parameter.

class Queue[T] private (
  private val leading: List[T], // leading can be seen for all instances(but not for their sub-class)
  private val trailing: List[T]
)

Companion Object

An apply factory method in a companion object.

object Queue {
  // constructs a queue with initial elements 'xs'
  def apply[T](xs: T*) = new Queue[T](xs.toList, Nil)
}

Variance Annotations

Queue is a trait and Queue[String] is a type. Queue is also called a type constructor.  In Scala, generic types is by default non variant (or “rigid”).

covariance

trait Queue[+T] {...}

controvariance

trait Queue[-T] {...}

Arrays are treated as covariant in Java, but Scala tries to be purer than Java, not treating Arrays as covariant.

variance annotations checking

class Queue[+T] {
  def enqueue(x: T) = 
    ...
}
Queues.scala: error: covariant type T occurs in contravariant position in type T of value x : def enqueue(x: T) =

Reassignable fields are a special case of the rule that disallows type parameters annotated with + from being used as method parameter types. As mentioned, a reassignable field, “var x: T”, is treated in Scala as a getter method, “def x: T”, and a setter method, “def x_=(y: T)”. As you can see, the setter method has a parameter of the field’s type T. So that type may not be covariant.

Lower Bound

class Queue[+T] (private val leading: List[T], private val trailing: List[T]) {
  def enqueue[U >: T](x: U) = 
    new Queue[U] (leading, x :: trailing) // ...
}

The new definition gives enqueue a type parameter U, and with the syntax, “U >: T”, defines T as the lower bound for U. As a result, U is required to be a super type of T. The parameter to enqueue is now of type U instead of type T, and the return value of the method is now Queue[U] instead of Queue[T].

Correcting the variance error by adding a lower bound makes enqueue more general and queues as a whole more usable.

Scala prefers declaration-site variance over use-site variance as it is found in Java’s wildcards. With use-site variance, you are on your own designing a class.

Example

Here is the demonstration of function type parameter variance.

class Publication(val title: String)
class Book(title: String) extends Publication(title)
object Library {
  val books: Set[Book] = 
    Set(new Book("Programming in Scala"), new Book("Walden"))
    def printBookList(info: Book => AnyRef) {
      for (book <- books) println(info(book))
    }
}
object Customer extends Application {
  def getTitle(p: Publication): String = p.title
  Library.printBookList(getTitle)
}
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s