Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extending a trait and types

Tags:

scala

I would like to have a sealed trait which have a declared method that returns the actual class that extends the trait. Should I use an abstract type, a parameter type or is there any other nice way to solve this?

sealed trait Foo {
  type T
  def doit(other: T): T
}

or

sealed trait Foo[T] {
  def doit(other: T): T
}

Note that T must be a subtype of Foo in this example. If I do it like this the type information feels too repeated:

case class Bar(name: String) extends Foo[Bar] {
  def doit(other: Bar): Bar = ...
}
like image 339
chrsan Avatar asked Nov 29 '10 11:11

chrsan


2 Answers

They are mostly interchangeable. According to Odersky, the reason was mainly for completeness: That similarly to the fact that methods and fields (values) can be either abstract or passed as parameters, so can types.

It is better to use an abstract type when you intend to mix several traits that all use the same type name. With type parameters you need to explicitly pass the type to each

Here's an article explaining all of this: http://www.artima.com/weblogs/viewpost.jsp?thread=270195

like image 145
IttayD Avatar answered Sep 28 '22 16:09

IttayD


You can cut down on the repetition somewhat by having your doit method return a factory function:

trait Foo[T] { 
   self: T =>
   def doit: T => T 
}

case class Bar(name: String) extends Foo[Bar] {
   // note: types omitted 
   def doit = { other => Bar(name + other.name) }
}

It's not possible to do the same with an abstract type:

trait Foo { 
   self: T => // won't compile because T isn't defined yet
   type T 
   def doit: T => T
}
like image 27
Aaron Novstrup Avatar answered Sep 28 '22 16:09

Aaron Novstrup