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?