This is the 4th post in the Scala vs. Kotlin focus series.Other posts include:
- Scala vs Kotlin: Pimp my library
- Scala vs Kotlin: Operator overloading
- Scala vs Kotlin: inline and infix
- Scala vs Kotlin: Multiple Inheritance and the Diamond problem (this post)
Inheritance is one of the basic tenet of Object-Oriented Programming, along with encapsulation and polymorphism. Alongside simple inheritance, there is multiple inheritance:
Multiple inheritance is a feature of some object-oriented computer programming languages in which an object or class can inherit characteristics and features from more than one parent object or parent class. It is distinct from single inheritance, where an object or class may only inherit from one particular object or class.
https://en.wikipedia.org/wiki/Multiple_inheritance
C++ is famous for allowing multiple inheritance, and describing the diamond problem. It states that there’s an issue when a child class inherits from multiple classes that have the same method.
C++ has its own way of coping with the diamond problem. In order to avoid it, Java completely disallows multiple-inheritance. Let’s check how Scala and Kotlin fare.
Scala
Scala doesn’t allow for multiple inheritance per se, but allows to extends multiple traits.
Traits are used to share interfaces and fields between classes. They are similar to Java 8’s interfaces. Classes and objects can extend traits but traits cannot be instantiated and therefore have no parameters.
http://docs.scala-lang.org/tutorials/tour/traits.html
The above diagram translates into the following code:
trait Openable {
def open() { ... }
}
trait Window extends Openable {
def open() { ... }
}
trait Door extends Openable {
def open() { ... }
}
class WindowDoor extends Door with Window {
...
}
Scala resolves the diamond problem by defining one main super trait - whose code will be used, among all super traits.
The main one is set with the extends
keyword, while other are with with
.
Hence, in the above example, WindowDoor.open()
will by default use code from Door.open()
.
Of course, nothing prevents us from overriding the method.
Kotlin
As in Scala, Kotlin doesn’t allow to extend multiple super classes. Yet, interfaces can have concrete functions.
Interfaces in Kotlin are very similar to Java 8. They can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state.
https://kotlinlang.org/docs/reference/interfaces.html
The following is the code above translated in Kotlin:
interface Openable {
fun open() { ... }
}
interface Window : Openable {
override fun open() { ... }
}
interface Door : Openable {
override fun open() { ... }
}
class WindowDoor : Door, Window {
override fun open() { ... }
}
Kotlin takes another path to solve the diamond problem: explicit overriding. The compiler detects diamond occurrences, and fires an error if a function is implemented by multiple parent classes. To fix this, the developer must explicitly code the desired behavior.
Conclusion
While Scala’s approach is more elegant, Kotlin’s is consistent with its philosophy: being explicit and readable before being concise.