Got lost in generics a bit. Is there any way to av...
# announcements
g
Got lost in generics a bit. Is there any way to avoid unchecked cast here?
Copy code
abstract class FSM<STEP : FSM.Step<DATA>, DATA>(firstStep: STEP) {

    var currentStep: STEP = firstStep
        private set

    fun next(data: DATA) {
        currentStep = currentStep.next(data)
    }
    
    fun prev(data: DATA) {
        currentStep = currentStep.prev(data)
    }

    interface Step<DATA> {
        fun next(data: DATA): Step<DATA>
        fun prev(data: DATA): Step<DATA>
    }
}
p
you do have an unchecked cast
currentStep.next
can return any subtype of
Step<DATA
and not just
STEP
k
Classic recursive generics:
Copy code
abstract class FSM<STEP : FSM.Step<DATA, STEP>, DATA>(firstStep: STEP) {

    var currentStep: STEP = firstStep
        private set

    fun next(data: DATA) {
        currentStep = currentStep.next(data)
    }

    fun prev(data: DATA) {
        currentStep = currentStep.prev(data)
    }

    interface Step<DATA, S: Step<DATA, S>> {
        fun next(data: DATA): S
        fun prev(data: DATA): S
    }
}
👆 2
1
Change
Step
to
Step<DATA, S: Step<DATA, S>>
and change
FSM
accordingly.
g
works wonders! Probably even covariant?:
Step<DATA, out S : Step<DATA, S>>
?
k
Depending on the intent, sure.
🙏 1
👌🏼 1
d
You could also declare the type of
currentStep
as
Step<DATA>
I think complex type relations should be avoided.
👍 1
g
True! A second working solution. The downside is,
currentStep
is public, so the usage is going to be strange. You feed your subclassed steps to FSM, but it gives you the superclass current.
d
Ah yeah, fair enough. Then Karel's solution is better :)