菱形継承問題

Scala のクラスは単一継承だけど、トレイトは複数継承できるので菱形継承問題が起きる。菱形継承問題というのは次のようなものだ。

greet メソッドを定義した TraitA と、それを継承してそれぞれ別の greet メソッドを実装した TraitB と TraitC があるとする。

scala> trait TraitA {
     |     def greet(): Unit
     | }
defined trait TraitA

scala> trait TraitB extends TraitA {
     |     def greet(): Unit = println("Good morning!")
     | }
defined trait TraitB

scala> trait TraitC extends TraitA {
     |     def greet(): Unit = println("Good evening!")
     | }
defined trait TraitC

ここで TraitB と TraitC の両方を継承したクラスを考えよう。すると、継承の系統図が菱形になる。で、どこが問題かというと、greet メソッドの実装が衝突している、ということだ。これを菱形継承問題という。

Scala で単純にこういう継承を作るとエラーになる。

scala> class ClassA extends TraitB with TraitC
<console>:13: error: class ClassA inherits conflicting members:
  method greet in trait TraitB of type ()Unit  and
  method greet in trait TraitC of type ()Unit
(Note: this can be resolved by declaring an override in class ClassA.)
       class ClassA extends TraitB with TraitC
             ^

TraitB と TraitC を継承した ClassA で greet メソッドが衝突していると怒られている。

これを解決するには ClassA で greet メソッドをオーバーライドしてやればいい。

scala> class ClassA extends TraitB with TraitC {
     |     override def greet(): Unit = println("How are you?")
     | }
defined class ClassA

継承元の TraitB の greet メソッドを呼び出したいときには次のように super キーワードを使う。[ ] の中に呼び出したいほうのトレイト名を書けばいい。

scala> class ClassB extends TraitB with TraitC {
     |     override def greet(): Unit = super[TraitB].greet()
     | }
defined class ClassB

呼び出した結果はそれぞれ次のようになる。

scala> (new ClassA).greet()
How are you?
scala> (new ClassB).greet()
Good morning!