How do I create custom `select` clauses? I have a...
# coroutines
c
How do I create custom
select
clauses? I have an event loop. I want to create a
select
clause that: • Registers an event handler to the loop • If any of the clauses is selected, unregisters the event handler from the loop
y
Isn't this just a normal
select
in a loop? Regardless, do remember that you can simply take in a
SelectBuilder
and use its pre-existing clauses as you wish, so you can make a complicated clause out of it. Do you have some example for the syntax and semantics you want?
c
Yes:
Copy code
class Router {
    // …

    suspend fun registerHandler(handler: Handler)

    suspend fun unregisterHandler(handler: Handler)
}

class Handler(
    val isApplicable: (Update) -> Boolean,
    val action: suspend (Update) -> Unit,
)

fun Message.replyHandler(
    action: suspend (Message) -> Unit,
) = Handler(
    isApplicable = { it is Message & it.replyTo == this.id },
    action = { action(it as Message) },
)
Expected usage:
Copy code
val message1 = …
val message2 = …

select {
    onTimeout(…) { … }
    message1.onReply {
        …
    }
    message2.onReply {
        …
    }
}
Registering the handlers I see how to do, by reusing the
Deferred.onAwait
clause, but I don't see how to unregister both handlers once one is triggered.
y
If you allow yourself a custom
select
wrapper, then:
Copy code
class MySelectBuilder(private val selectBuilder: SelectBuilder) {
  private val registered = mutableListOf<Handler>()
  private fun unregisterAll() = registered.forEach { unregisterHandler(it) }
  fun Message.onReply(action: suspend (Message) -> Unit) = with (selectBuilder) {
    val handler = replyHandler(action)
    registered.add(handler)
    async {
      ...
    }.onAwait {
      unregisterAll()
      ...
    }
  }
  fun onTimeout(...) = selectBuilder.onTimeout {
    unregisterAll()
    ...
  }
}
suspend fun mySelect(block: MySelectBuilder.() -> Unit) = select { block(MySelectBuilder(block)) }
c
Yeah, I was thinking that a custom
select
wrapper is the best way to go