Lets say i have a class with chaining functions
class Vehicle {
protected var position: (Int, Int) = (0, 0)
def moveLeft(meters: Int): Vehicle = {
position = position._1 - meters -> position._2
this
}
def moveForward(meters: Int): Vehicle = {
position = position._1 -> (position._2 + meters)
this
}
}
so each method returns instance itself
Now i want to inherit Vehicle and add some method to new class
class Helicopter extends Vehicle {
protected var verticalDimension: Int = 0
def flyIntoTheSky(meters: Int): Helicopter = {
verticalDimension += meters
this
}
}
If i will create a new class instance and call any functions from parent, for example
new Helicopter().moveLeft(10).moveForward(20)
i will not be able to call new class method flyIntoTheSky because methods return type is Vehicle, and Vehicle does not know anything about methods of Helicopter.
2 obvious ways to solve it: Either using asInstanceOf
new Helicopter()
.moveLeft(10)
.moveForward(20).asInstanceOf[Helocopter]
.flyIntoTheSky(10000)
either overriding each and avery parental method in new class
Both ways are not looking nice, i would prefer to leave all this type issues to Vehicle class and forget about it, so i found(as i hoped) the solution, rewriting methods like this
def moveLeft[T](meters: Int, vehicle: T = this): T = {
position = position._1 - meters -> position._2
this.asInstanceOf[T]
}
so i expected that return type will be taken from method's second parameter vehicle, which always equals to default value "this", and will return the value of current type. But unfortunately
new Helicopter().moveLeft(10)
still returns value of type Vehicle res0: Vehicle = Helicopter@1de81c37
So the first question: why it doesn't work as i expected. And the second: is there are any beautiful way to solve this problem
Thank you
PS In google i found this solution in Java https://www.andygibson.net/blog/article/implementing-chained-methods-in-subclasses/ , but i dont know java and can not translate it in scala
If the method always returns this
you can give it return type this.type
.
def moveLeft(meters: Int): this.type = {
position = position._1 - meters -> position._2
this
}