Scala Design Patterns.
上QQ阅读APP看书,第一时间看更新

Same signatures and different return types mixins

As expected, the previous problem does not exist when input parameters to the methods differ either by type or by count since this is a new signature. However, the problem will still be there if we have the following two methods in our traits:

def value(a: Int): Int = a // in trait A
def value(a: Int): String = a.toString // in trait B

You will be surprised to see that the approach we used will not work here. If we decide to override only the value method in the A trait, we will get the following compilation error:

Error:(19, 16) overriding method value in trait B of type (a: Int)String;
method value has incompatible type
override def value(a: Int): Int = super[A].value(a)
^

If we override the value method in the B trait, the error will change respectively.

If we try and override both, then the error will be as follows:

Error:(20, 16) method value is defined twice
conflicting symbols both originated in file '/path/to/traits/src/main/scala/com/ivan/nikolov/composition/Clashing.scala'
override def value(a: Int): String = super[B].value(a)

This shows that Scala actually prevents us from doing some dangerous things that can occur in multiple inheritance. For the sake of completeness, if you face a similar issue, there is a workaround (by sacrificing the mix in functionality). It will look as follows:

trait C {
def value(a: Int): Int = a
}

trait D {
def value(a: Int): String = a.toString
}

object Example {

val c = new C {}
val d = new D {}

def main (args: Array[String]): Unit = {
System.out.println(s"c.value: ${c.value(10)}")
System.out.println(s"d.value: ${d.value(10)}")
}
}

The preceding code uses traits as collaborators, but it also loses the fact that the class that uses them is also an instance of the trait type, which can be useful for other operations as well.