I'm working my way through Odersky's Programming in Scala and I'm looking at the chapter on traits. He gives an example where various traits/classes are linearized and says this:
Cat -> FourLegged -> HasLegs -> Furry -> Animal -> AnyRef -> Any
When any of these classes and traits invokes a method via super, the implementation invoked will be the first implementation to its right in the linearization.
I've defined classes/traits as follows:
abstract class Animal { def hi }
class Cat extends Animal { def hi { println("cat") } }
trait Furry extends Animal { abstract override def hi {
println("furry"); super.hi } }
and done
val c = new Cat with Furry
c.hi
and I get
furry
cat
According to the book, the super in furry should call Animal.hi
Since Animal is abstract, that should either cause a compile error or a runtime error I would have thought. Instead it calls cat.hi
What am I missing? I thought the Cat class would appear first in the linearization, and therefore there is no way that a super
call could call it?
(I missed out HasLegs and FourLegged to keep it simpler)
I suspect they've mis-stated the linearization order?
Thanks!
EDIT: Following user2357112's comment below, I tried mixing in the Furry trait statically:
scala> class Cat extends Animal with Furry { def hi { println("cat") } }
<console>:13: error: overriding method hi in trait Furry of type => Unit;
method hi needs `override' modifier
class Cat extends Animal with Furry { def hi { println("cat") } }
I'm now rather confused as I thought that it didn't make a difference whether you mixed in a trait at runtime or in the code. But here, the runtime mixin executes without error, but I get a compile error if I try to mix it in in code. What gives?