sockeqwe
sockeqwe

Reputation: 15929

Generics in Objects

I have a question about sealed class, generics and object.

Let's say I would like to model something like 3 finite cases with a sealed class something like this:

sealed class ChangeState<S> {
   fun reduceState(state: S): S
}

data class SetState<S>(val newState: S) : ChangeState<S>() {
    override fun reduce(state: S): S = newState
}

object NoStateChange : ChangeState<Nothing>() {  // What do I specify here for ChangeState? Nothing?

    override fun reduce(state: Nothing): Nothing {
        throw Exception("This should never be called")
    }
}

The goal is to provide a convenient way to define NoStateChange in a generic way that it can be used as following:

fun foo(i : Int) : ChangeState<Int> {
   return if (i==0)
            NoStateChange  // Won't compile because return type is ChangeState<Nothing> but expected ChangeState<Int>
          else 
            SetState(i)

}

Is there a way to do that with object and Generics somehow?

Upvotes: 1

Views: 42

Answers (1)

sockeqwe
sockeqwe

Reputation: 15929

As pointed out by @Tenfour04 the issue is that out is needed but reduceState() would require in as well. However, reduceState() can be refactored out of the class hierarchy and moved to an extension function like that:

sealed class ChangeState<out S>

data class SetState<S>(val newState: S) : ChangeState<S>() 

object NoStateChange : ChangeState<Nothing>()



fun <S> ChangeState<S>.reduce(state: S): S {
    return when (val change = this) {
        is SetState -> change.newState
        is NoStateChange -> state 
    }
}

Upvotes: 2

Related Questions