Sam Stites

Trait Similarity to Classes

Traits can have constructors! Wow, I wasn’t expecting that one. Just like a class, the constructor is embedded in the body of the trait itself. Every trait has one parameterless constructor. The fact that a trait has a parameterless constructor is the only technical difference between traits and classes. So anything you can do with a class, you can do with a trait!

trait Foo {
  def bar(x: String)
  def log(y: String) {}

  // part of the constructor
  val baz = 10
  out.println('bats')
}

Trait constructors execute in the following order:

If we want to evaluate some inherited logic from the fields of the file logger, because of the construction order we need have one of two options: lazy evalutaion, or early definition blocks. In some class Foo which inherits from a FileLogger:

trait FileLogger extends Logger {
  val filename: String
  lazy val out = new PrintStream(filename)
  def log(msg: String) { out.println(msg) } // No override needed
}

Evaluating out lazyly will give us time to instantiate filename before running out. Alternatively we can define filename early in an instance:

val foo = new { val filename = "myapp.log" } with Foo with FileLogger

or in the class definition:

class Foo extends {
  val filename = "savings.log"
} with Account with FileLogger {
  // Foo implementation
}

Since traits are technically the same as a class, but with that one hitch of being parameterless, it stands that a trait can extend a class and make it a superclass of any class mixing the trait.

For example we have a trait Foo extends ClassSuper and a class Sub extends Foo. Then the superclass of Foo, ClassSuper will be passed on to become the superclass of Sub. This is even okay if our class extends a seperate class and only uses Foo as a trait so long as all classes are a subclasses of the trait’s superclass. Only one superclass can exist.