Inheritance is one of the basic tenets 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.
— Wikipedia
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 us to extend 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.
— Scala Documentation
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 the others are set 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 us 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.
— Kotlin Documentation
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.
Comments