Abstract fields in traits (Scala) - construction order

inheritance, multiple-inheritance, scala, traits

Solution

Your construction order is entirely wrong. :-)

The first thing to be constructed is the class, then you go through the traits from left to right. It's a bit more complex to that -- there's linearization rules that deal with traits inherited multiple times, but that's about it.

So:

- Account

- Logged

- SavingsAccount

- ConsoleLogger

- ShortLogger

- Anonymous subclass

Now, to your question:

val acct = new SavingsAccont with FileLogger {
  val filename = "myapp.log" // Does not work
}

val acct = new {
  val filename: "myapp.log"
} with SavingsAccount with FileLogger

Note that the block of code comes first in the second example. That's known as early initialization, and what it does is to apply that initialization before anything else.

Problem

So I'm reading the Scala for the Impatient book and one of the examples it uses is a `Logger` trait that essentially prints a `String` to some stream. In the example, it has a trait `ConsoleLogger` (which extends `Logger`) that prints the message out to `stdout` and `ShortLogger` (also extends `Logger`) that simply truncates the string if the length is too long. To change the maximum length of `ShortLogger` the book proposes uses an anonymous subclass, something like: ``` val acct = new SavingsAccount with ConsoleLogger with ShortLogger { val maxLength = 20 } ``` Where `ShortLogger` is a trait with an abstract `maxLength: Int` field and `SavingsAccount` is defined as ``` class SavingsAccount extends Account with Logged { ... } ``` Which makes sense to me (kind of). I'm assuming the construction order is: - `Logger` gets constructed first (since it is a super-trait of `ConsoleLogger`), - `ConsoleLogger` - `ShortLogger` - `Account` - `SavingsAccount`. - Then we have the anonymous subclass construction where we define the abstract `maxLength = 20`. However, later on in the book, it gives a new `Logger` sub-trait: ``` trait FileLogger extends Logger { val filename: String val out = new PrintStream(filename) def log(msg: String) { out.println(msg); out.flush() } } val acct = new SavingsAccont with FileLogger { val filename = "myapp.log" // Does not work } ``` It says it does not work due to the construction order. They propose the modification: ``` val acct = new { val filename: "myapp.log" } with SavingsAccount with FileLogger ``` However, this definition seems to be similar to the one above with `maxLength`, so what am I missing between the above example and the bottom example?

Original source

Related problems