Jordan Parmer
Jordan Parmer

Reputation: 37164

Why would I use type T = <type> instead of trait[T]?

Here is an observation I've had from a chapter in Programming Scala.

In Scala, I often see the abstract trait pattern:

trait Abstract {
  type T
  def transform(x: T): T
  val initial: T
  var current: T
}

class Concrete extends Abstract {
  type T = String
  def transform(x: String) = x + x
  val initial = "hi"
  var current = initial
}

Why would I choose the abstract trait pattern over parameterized generics?

trait Abstract[T] {
  def transform(x: T): T
  val initial: T
  var current: T
}

class Concrete extends Abstract[String]{
  def transform(x: String): x + x
  val initial: "hi"
  var current: initial
}

Upvotes: 2

Views: 75

Answers (1)

lmm
lmm

Reputation: 17431

The two approaches are mostly equivalent. One reason we might prefer a type member is so that methods can be written with dependent types rather than having to be generic:

def doSomethingWith(a: Abstract): a.T = ...

is arguably more readable than

def doSomethingWith[T](a: Abstract[T]): T = ...

at least as the signatures get more complicated (particularly if we're doing type-level programming, using Abstract as a type-level function).

There might be also implications for type inference; I don't know precisely how scala type inference works, but as far as I can tell there's no way to partially specify the types of a function:

def functionWeWantToCall[U, V, W](a: Abstract[U], b: Abstract[V], c: Abstract[W])
functionWeWantToCall[String, _, _](x, y, z) //won't compile

def functionWeWantToCall(a: Abstract, b: Abstract, c: Abstract)
functionWeWantToCall(x: Abstract{type T = String}, y, z) //works

So that's a reason I've sometimes found myself using the type member approach.

Also, of course, some people (e.g. those from an ML background) simply find the type member approach more familiar or readable.

Upvotes: 3

Related Questions