Scala trait linearization equivalent in Kotlin

60 Views Asked by At

I'm migrating some Scala code to Kotlin, that uses method linearization in a hierarchy of clasess and interfaces (traits in Scala jargon).

Does Kotlin have something equivalent? Any workaround? https://www.geeksforgeeks.org/trait-linearization-in-scala/

Here is a simple Scala example that uses linearization:

class old_Car 
{ 
    def method: String= "old car "
} 
  
// defining new_Car_Designs trait 
trait new_Car_Designs extends old_Car 
{ 
    override def method: String ="Designing-> "+ super.method 
} 
  
// defining new_Car_Part trait 
trait new_Car_Part extends old_Car 
{ 
    override def method: String = "Add new part-> "+ super.method 
} 
  
// defining new_Car_Paint trait 
trait new_Car_Paint extends old_Car 
{ 
    override def method: String = "Repainting-> "+ super.method 
} 
  
// defining new_Car class 
class new_Car extends new_Car_Paint with 
new_Car_Part with new_Car_Designs 
{ 
    override def method: String = "new car-> "+ super.method 
} 
  
// Creating object 
object geekforgeeks 
{ 
    // Main method 
    def main(args: Array[String]) 
    { 
        // new_Car object 
        var car1 = new new_Car 
        println(car1.method) 
    } 
} 

Output:

new car-> Designing-> Add new part-> Repainting-> old car

Related info:

1

There are 1 best solutions below

1
broot On BEST ANSWER

I don't think this is possible in Kotlin by using language features. This is consistent with the language goals. Kotlin favors composition and delegation over inheritance and especially multi-inheritance.

But no matter which language we use, this problem can be solved with traditional OOP patterns - again: composition and delegation. Kotlin can help with this and the resulting code is very similar to the original Scala code. Conceptually, it works a little differently, relations between objects are more explicit, but at least for me personally this is even better, this is cleaner:

interface Car {
    val method: String
}

class OldCar : Car {
    override val method = "old car "
}

class OldCarDesigns(private val delegate: Car) : Car by delegate {
    override val method = "Designing-> " + delegate.method
}

class OldCarPart(private val delegate: Car) : Car by delegate {
    override val method = "Add new part-> " + delegate.method
}

class OldCarPaint(private val delegate: Car) : Car by delegate {
    override val method = "Repainting-> " + delegate.method
}

class NewCar private constructor(private val delegate: Car) : Car by delegate {
    constructor() : this(OldCarDesigns(OldCarPart(OldCarPaint(OldCar()))))

    override val method = "new car-> " + delegate.method
}

fun main() {
    val car = NewCar()
    println(car.method)
}

We don't necessarily need all these Car by delegate as we override the only member anyway, but if we have more members and would like to override them selectively, then this is helpful. Alternatively, we can introduce an abstract DelegatingCar which would do the delegation, but I think it doesn't add too much value.

Chain of cars: OldCarDesigns(OldCarPart(OldCarPaint(OldCar()))) is ugly. If we like, we can create a helper function instead:

fun <T> T.linearize(vararg wrappers: (T) -> T) = wrappers.fold(this) { it, wrapper -> wrapper(it) }

constructor() : this(OldCar().linearize(::OldCarPaint, ::OldCarPart, ::OldCarDesigns))

Frankly speaking, NewCar doesn't feel very Kotlin-ish. In Kotlin, we usually avoid defining new types if their main/sole purpose is to create a graph of other objects. We prefer factory functions over new types.

BTW, ordering of your functions feels strange to me: new car -> designing -> adding part -> painting -> old car. Didn't you mean that the new car is based on a painted car, which in turn works on a car with added part, which works on redesigned car, which uses the old car as a base? It confused me a little when I was writing my answer ;-)