0

So, I'm working on a concept that involvs writing automatically to a ByteBuffer the content of a class extending Bufferizable

abstract class Bufferizable {

    abstract val fieldOrder: Array<String>

    open fun size(): Int = TODO()

    var initialized = false

    open infix fun to(address: Long) {

        if (initialized) {

            addFunctions.forEach {  }

        } else {

            addFunctions = Array(fieldOrder.size) { null }
            members = Array(fieldOrder.size) { null }

            fieldOrder.forEachIndexed { i, field ->
                val member = this::class.declaredMemberProperties.find { it.name == field }!!
                addFunctions[i] = when (member.returnType) {
                    Mat4::class.defaultType.javaType -> WithAddress::addMat4
                    ...
                    else -> throw Error()
                } as BufferizableAddFunctionType
                members[i] = member.get(this) // error
            }

            initialized = true
        }
    }

    infix fun from(address: Long): Unit = TODO()

    var addFunctions = arrayOf<BufferizableAddFunctionType?>()
    var members = arrayOf<Any?>()
}

typealias BufferizableAddFunctionType = (Any) -> Unit

object WithAddress {

    var address = NULL
    var offset = 0

    fun addMat4(mat4: Mat4) {
        for (i in 0..3)
            for (j in 0..3) {
                memPutFloat(address + offset, mat4[i, j])
                offset += Float.BYTES
            }
    }
    ...
}

The idea is to declare, for example, the following

object uboVS : Bufferizable() {

    var projectionMatrix = Mat4()
    var modelMatrix = Mat4()
    ...

    override val fieldOrder = arrayOf("projectionMatrix", "modelMatrix", "viewMatrix")
}

And then whenever uboVS to address will be called for the first time, it will be initialized and then its content written at the native address, following the order specified.

But the only problem I'm stuck at, is collecting the members to pass later on as argument to the i-th addFunction

because the compiler complains here:

members[i] = member.get(this)

Error:(328, 37) Kotlin: Out-projected type 'KProperty1' prohibits the use of 'public abstract fun get(receiver: T): R defined in kotlin.reflect.KProperty1'

How can I solve?

elect
  • 6,765
  • 10
  • 53
  • 119

1 Answers1

4

This is an inheritance problem. Your reflection call this::class.declaredMemberProperties.find{ ... } returns a KProperty1<out Bufferizable, Any?> This means a property from something that inherit from Bufferizable (See declaration-site variance for more information about out). Through the copiler does not know to which class this property belongs it does not allow a direct access. To solve this you have to access the getter function:

members[i] = member.getter.call(this)

Through the getter function belongs to the object and not to the reflection api it follows the default inheritance behavior and can be called.

pixix4
  • 1,271
  • 1
  • 13
  • 13