Simplify type signatures


Hi, Is there a way to simplify the following code

sealed class Async_load_state<WaitT, ErrorT, DoneT> () {
    class Wait<WaitT, ErrorT, DoneT>(val wait: WaitT): Async_load_state<WaitT, ErrorT, DoneT>() {}
    class Error<WaitT, ErrorT, DoneT>(val error: ErrorT): Async_load_state<WaitT, ErrorT, DoneT>() {}
    class Done<WaitT, ErrorT, DoneT>(val done: DoneT): Async_load_state<WaitT, ErrorT, DoneT>() {}

    fun is_done(): Boolean  {
        return when(this) {
            is Async_load_state.Error<*, *, *> -> true
            is Async_load_state.Done<*, *, *> -> true
            else -> false

class Async_load<WaitT, ErrorT, DoneT> (
        val w: WaitT,
        f: Async_load<WaitT, ErrorT, DoneT>.(WaitT) -> Unit) {

    var state: Async_load_state<WaitT, ErrorT, DoneT> = Async_load_state.Wait<WaitT, ErrorT, DoneT>(w)
    init { f(w) }

    fun error(error: ErrorT) {
        state = Async_load_state.Error<WaitT, ErrorT, DoneT>(error)

    fun done(done: DoneT) {
        state = Async_load_state.Done<WaitT, ErrorT, DoneT>(error)


Intuitively, <WaitT, ErrorT, DoneT> appears way too many times.



No, there isn’t


Use W, E and D instead? Generic arguments are a single letter for a reason :slight_smile:

Joking aside, generic parameters can easily propagate and explode - generics should be used judiciously


Maybe you could use type aliases.


the problem with it is that you need to pass the generics from the base classes to the superclasses.
a type alias is not going to help with passing generics through


IIRC, in other languages, one can write this as:

data AsyncLoad WaitT ErrorT DoneT =
Wait WaitT | Error ErrorT | Done DoneT

where *T are type variables and Wait/Error/Done are constructors.

In this particular case I was not sure if:

  1. There was an easier way to do this in Kotlin but I was unaware of it OR
  2. Kotlin is slightly more verbose

It looks like we on agreeing on 2.


I do not really understand what your code should do. What are WaitT ErrorT and DoneT should represent? It seems that they are used only internally, why make class generic at all?


Can you replace

class Done<WaitT, ErrorT, DoneT>(val done: DoneT): Async_load_state<WaitT, ErrorT, DoneT>() {}


class Done<DoneT>(val done: DoneT): Async_load_state<Nothing, Nothing, DoneT>()


That would require all the type parameters to be declared out. This would also result in any type Done<T> to be a subtype of all Async_load_state<W,E,D>, where T is a subtype of D, whereas in the current solution it would only be a subtype of a single instance type of Async_load_state.