Same signatures and return types mixins
Before going further, a quick reminder that a mixin is just a trait that has some code implemented inside. This means that in the following examples, we do not have to implement the methods inside the class that uses them.
Let's have a look at the following example:
trait A {
def hello(): String = "Hello, I am trait A!"
}
trait B {
def hello(): String = "Hello, I am trait B!"
}
object Clashing extends A with B {
def main(args: Array[String]): Unit = {
System.out.println(hello())
}
}
Probably as expected, our compilation will fail with the following message:
Error:(11, 8) object Clashing inherits conflicting members:
method hello in trait A of type ()String and
method hello in trait B of type ()String
(Note: this can be resolved by declaring an override in object Clashing.)
object Clashing extends A with B {
^
The message is useful and it even gives us a hint about how to fix the problem. Clashing methods is a problem in multiple inheritances, but as you can see, we are forced to pick one of the available methods. Here is a possible fix inside the Clashing object:
override def hello(): String = super[A].hello()
However, what if we want to use both the hello methods for some reason? In this case, we can create other methods that are named differently and call the specific traits as in the preceding example (the super notation). We can also directly refer to the methods with the super notation instead of wrapping them in a method. My personal preference, though, would be to wrap it, as the code could get messy otherwise.
What would happen if in the preceding example, instead of super[A]. hello(), we do the following: override def hello(): String = super.hello()?
Which hello method will be called and why? In the current case, it will be the one in the B trait and the output will be Hello, I am trait B! This depends on linearization in Scala, and we will be looking at this later in this chapter.