I need to define some binary operation (like matrix addition) for some base class, but need it to return derived class if applied to derived class. For this I need to clone derived class without knowing it's class at compile time, for example
class Matrix private constructor(private val data: DataClass) {
public constructor(...) : this(...) {
...
}
operator fun times(ano: Matrix) : Matrix {
return Matrix(data.specialOp(ano.data))
}
}
class EnhancedMatrix {
...
}
fun main() {
val a = EnhancedMaptrix(...)
val b = EnhancedMaptrix(...)
val c = a * b;
println(c is EnhancedMartrix) // should be true w/o explicit overriding of `times`
}
Is it possible?
CodePudding user response:
Probably the easiest way without using a reflection is to provide a factory by the subclass:
open class Matrix(
private val data: DataClass,
private val factory: (DataClass) -> Matrix
) {
operator fun times(ano: Matrix) : Matrix {
return factory(data.specialOp(ano.data))
}
}
class EnhancedMatrix(data: DataClass) : Matrix(data, ::EnhancedMatrix)
Also, if we would like c
to not only be initialized at runtime to EnhancedMatrix
object, but also to be resolved to EnhancedMatrix
type at the compile time, then this is more complicated, but still possible. We have to use self-referencing generic type like this:
open class Matrix<T : Matrix<T>>(
val data: DataClass,
private val factory: (DataClass) -> T
) {
operator fun times(ano: Matrix<*>) : T {
return factory(data.specialOp(ano.data))
}
}
class EnhancedMatrix(data: DataClass) : Matrix<EnhancedMatrix>(data, ::EnhancedMatrix)
Matrix
is parameterized by its specific type, so if we use times()
on EnhancedMatrix
(which is Matrix<EnhancedMatrix>
) then it itself returns EnhancedMatrix
as well. Just be aware this solution is pretty complicated, it isn't easy to understand, so use it only if really needed.
CodePudding user response:
Probably not what you want but could you just provide a secondary constructor for EnhancedMatrix that take a Matrix as the argument?
open class Matrix {
operator fun times(ano: Matrix) : Matrix {
return Matrix()
}
}
class EnhancedMatrix() : Matrix() {
constructor(m: Matrix) : this() { }
}
fun main() {
val a = EnhancedMatrix()
val b = EnhancedMatrix()
val c = EnhancedMatrix(a * b)
println(c is EnhancedMatrix) // should be true w/o explicit overriding of `times`
println(c is Matrix)
}