Skip to content

Channels

Calibre provides Channel:<T> for passing values between concurrent tasks.

Note that unlike in Go, Channels in Calibre hold a queue of values.

let mut jobs : Channel:<int> = Channel:<int>.new();
let mut results : Channel:<int> = Channel:<int>.new();

A channel stores values of a single element type.

The basic operations are sending and receiving.

jobs.send(10);
let value := jobs.get();
print(value);

get() returns an option because a receive may fail or the channel may be empty or closed.

if let .Some : value <- jobs.get() => {
print(value);
};

Channels are especially useful with spawned workers.

const worker := fn (jobs : &Channel:<int>, results : &mut Channel:<int>) => {
if let .Some : job <- jobs.get() => {
results.send(job * 2);
};
};

The stdlib provides these important channel operations:

  • Channel.new()
  • .send(...)
  • .get()
  • .try_get()
  • .try_send(...)
  • .close()
  • .closed()
  • .recv()
  • .try_recv()
  • .recv_or(...)
  • .send_all(...)

Closing a channel marks it as done.

jobs.close();
print(jobs.closed());

Channels also work with select, which lets the program react to whichever communication is ready.

select {
value <- results => {
print(value);
},
_ => {}
};

This makes channels a natural choice for worker pools, pipelines, task queues, and async coordination between spawned tasks.