2

I have the following abstract class

abstract class Vec2t<T : Number>(open var x: T, open var y: T)

implemented by

data class Vec2(override var x: Float, override var y: Float) : Vec2t<Float>(x, y)

So far, everything works just fine

Now, I'd like to do something similar for the matrices, this is at the moment my abstract class

abstract class Mat2t<T : Number>(open var value: Array<out Vec2t<T>>)

that should be implemented by

class Mat2(override var value: Array<Vec2>) : Mat2t<Float>(value)

But compiler complains on Array<Vec2>:

Error:(8, 32) Kotlin: Type of 'value' doesn't match the type of the overridden var-property 'public open var value: Array> defined in main.mat.Mat2t'

I was told:

  • I can't change the type of a var property when I override it (but actually I am not really changing it, I am overriding it with a subtype.. is it the same thing?)
  • mat2.value = object : Vec2t<Float>() { ... } would not be valid, which must not be the case for any subclass of Mat2t<Float>

How may I overcome these problems?

Is there a way to have an abstract generic class Mat2t with a generic array and implement it with a subtype array?

elect
  • 6,765
  • 10
  • 53
  • 119

1 Answers1

4

You can accomplish this by making your generic parameter a subtype of Vec2t instead of a subtype of Vec2t's generic parameter type (T : Number):

abstract class Mat2t<T : Vec2t<*>>(open var value: List<T>)

class Mat2(override var value: List<Vec2>) : Mat2t<Vec2>(value)

Note that as you are overriding var value you don't need to have it in the abstract class constructor. The same applies for Vec2t. e.g.:

abstract class Vec2t<T : Number> {
    abstract var x: T
    abstract var y: T
}

class Vec2(override var x: Float, override var y: Float) : Vec2t<Float>()

abstract class Mat2t<T : Vec2t<*>> {
    abstract var value: List<T>
}

class Mat2(override var value: List<Vec2>) : Mat2t<Vec2>()

These abstract classes could then even be represented as interfaces instead if that suits you:

interface Vec2t<T : Number> {
    var x: T
    var y: T
}

data class Vec2(override var x: Float, override var y: Float) : Vec2t<Float>

interface Mat2t<T : Vec2t<*>> {
    var value: List<T>
}

data class Mat2(override var value: List<Vec2>) : Mat2t<Vec2>
mfulton26
  • 29,956
  • 6
  • 64
  • 88
  • it works, nice. I see you used `List` over `Array`, is there a specific reason? To get covariance? For reference, I am trying to do a port of [this](https://github.com/g-truc/glm/blob/master/glm/detail/type_mat2x2.hpp). Cool tip about the interfaces, +1 – elect Nov 10 '16 at 14:39
  • @elect Habit I suppose. I almost never use `Array`. Plus I see your `Vec2` is a `data class` which leads me to believe you might want `Mat2` to be a `data class` as well in which case you would have to override `equals` and `hashCode` yourself if you used `Array` (it doesn't implement them) but with a `List` the compiler takes care of it for you. See also http://stackoverflow.com/q/36262305/3255152. – mfulton26 Nov 10 '16 at 15:02
  • FYI: I'm not sure exactly what you are after but there are various linear algebra / matrix Java libraries out there: http://stackoverflow.com/questions/10815518/java-matrix-libraries. Maybe one of them already meets your use case; maybe not. Enjoy! – mfulton26 Nov 10 '16 at 15:12
  • just a kotlin glm porting – elect Nov 10 '16 at 17:46