Coordinate channels with select
This deterministic example prepares a buffered channel before each select so both the ready and default paths are visible.
Source
ts
import go fmt from "fmt";
function receive(ready: boolean): bstring {
const channel = goChannel[int](1);
if (ready) { channel <- 42; }
select {
case const value = <-channel { return "value:" + fmt.Sprint(value); }
default { return "idle"; }
}
}
function send(full: boolean): string {
const channel = goChannel[int](1);
if (full) { channel <- 1; }
select {
case channel <- 2 { return "sent"; }
default { return "blocked"; }
}
}
function main(): void {
fmt.Println(receive(true), receive(false));
fmt.Println(send(false), send(true));
}Run
sh
keika check select.km
keika run select.kmExpected output:
text
value:42 idle
sent blockedSelection contract
- A receive case is ready when a value can be received immediately.
- A send case is ready when the send can proceed immediately.
defaultruns only when no communication case is ready.- Without
default, select waits until a case becomes ready. - If several cases are ready, Go chooses one pseudo-randomly.
- Case declarations have case-block scope and do not leak.
Checked receive is also accepted:
ts
select {
case const [value, open] = <-channel {
if (!open) { return; }
consume(value);
}
}Select preserves Go evaluation and channel panic/blocking behavior. It does not add cancellation automatically; select on an explicit context.Context.Done() channel when needed.
See Concurrency.