Martin
Martin

Reputation: 814

How to do Kotlin type inference from KClass reflection?

In the code below, I'm having trouble arranging the in/out correctly such that both from() and to() work as expected. I've tried switching in/out in both properties and function parameters, but always end up with incorrect typing errors.

class KStateMachine(private val states: List<StateHandler>) {

var currentState: KClass<out StateHandler>
    private set
private val handlers:HashMap<KClass<in StateHandler>, Int> = HashMap()

init {
    currentState = states[0]::class

    for (i in 0..states.size - 1) {
        handlers.put(states[i]::class, i)
    }
}

fun goto(toState: KClass<in StateHandler>) {
    var index = handlers.get(toState)
    if (index != null) {
        var oldState = currentState
        currentState = toState
        states.get(index).from(oldState)
    } else {
        throw RuntimeException("to state unknown")
    }
}

inline fun <reified T: StateHandler> goto() {
    goto(T::class)
}

abstract class StateHandler {
    abstract fun from(fromState: KClass<in StateHandler>)
}
}

Upvotes: 2

Views: 727

Answers (1)

hotkey
hotkey

Reputation: 148169

I suppose you don't need the in-projections at all for the KClasses: your code doesn't seem to pass a StateHandler or something parameterized with StateHandler into the functions of KClass.

If the intention of the variance is that you want all the KClasses to represent subtypes of StateHandler, then you could do with out-projections everywhere:

class KStateMachine(private val states: List<StateHandler>) {

    private var currentState: KClass<out StateHandler>
    private val handlers: HashMap<KClass<out StateHandler>, Int> = HashMap()

    init {
        currentState = states[0]::class

        for (i in 0..states.size - 1) {
            handlers.put(states[i]::class, i)
        }
    }

    fun to(toState: KClass<out StateHandler>) {
        var index = handlers.get(toState)
        if (index != null) {
            var oldState = currentState
            currentState = toState
            states.get(index).from(oldState)
        } else {
            throw RuntimeException("to state unknown")
        }
    }

    abstract class StateHandler {
        abstract fun from(fromState: KClass<out StateHandler>)
    }
}

Upvotes: 1

Related Questions