Reputation: 7320
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
. 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?
Upvotes: 3
Views: 656
Reputation: 297205
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:
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.
Upvotes: 6