Diamond Problem and Scala Traits
The diamond problem is a classic multiple inheritance puzzle: when classes B and C both inherit from A, and class D inherits from both B and C, which version of A’s overridden method does D use?
Java sidesteps this entirely by disallowing multiple class inheritance — you can implement multiple interfaces, but interfaces (pre-Java 8) can’t carry method implementations. The problem just doesn’t arise.
Scala takes a different approach with traits, inspired by Ruby’s mixin pattern. Traits can carry full method implementations, and Scala resolves the diamond problem through linearization — the order in which traits are declared determines method resolution priority.
A Concrete Example
abstract class A {
def isWhat(): Boolean
}
trait B extends A {
override def isWhat(): Boolean = true
}
trait C extends A {
override def isWhat(): Boolean = false
}
val a = new A with C with B
println(a.isWhat()) // Output: trueThe declaration new A with C with B gives B precedence because it appears last. In Scala’s linearization, the rightmost trait wins. So isWhat() returns true.
Flip the order — new A with B with C — and you get false.
The Trade-off
This places the resolution responsibility squarely on the developer. It’s explicit and deterministic once you understand linearization, but it’s also easy to introduce subtle bugs if you’re not thinking carefully about trait ordering.
Beyond Multiple Inheritance
The real power of traits isn’t just solving the diamond problem — it’s that they enable partial implementation sharing in ways Java interfaces (pre-Java 8) simply can’t. You can compose behaviors from multiple traits without the awkward workarounds of abstract classes and delegation.
(Written while enjoying Scala on a newly purchased MacBook Pro. Early impressions: quite liked both.)