Fibers and Concurrency
Fibers are lightweight concurrent computations. They are constructed as values of Fiber<T> and communicate through Channel<T>. There are no OS threads exposed to user code; the runtime schedules fibers cooperatively. Values cross fiber boundaries — spawn captures and channel send — by move or copy, never by sharing ([MEM-FIBER-ISOLATION] in Memory Management).
Status
spawn, await, yield, and basic channel operations are implemented. The select expression and the fiber-isolated module system below are planned and not yet wired through code generation.
Core Types
FiberT> // a concurrent computation that produces a value of type T
ChannelT> // an in-process communication channel carrying values of type T
Constructing Fibers
Fibers are constructed using ordinary record-construction syntax:
let task = Fiberint> {
computation: fn() => calculatePrimes(n: 1000)
}
spawn <expr> is sugar for the equivalent Fiber construction:
let result = spawn 42
// equivalent to:
let result = Fiberint> { computation: fn() => 42 }
Constructing Channels
let sync = Channelint> { capacity: 0 } // unbuffered (rendezvous)
let buf = Channelstring> { capacity: 10 } // buffered
Operations
| Operation | Signature |
|---|---|
| Wait for a fiber to produce its value | await(fiber: Fiber<T>) -> T |
| Send a value to a channel | send(channel: Channel<T>, value: T) -> Result<unit, ChannelError> |
| Receive a value from a channel | recv(channel: Channel<T>) -> Result<T, ChannelError> |
| Yield to the scheduler | yield() -> unit |
Producer / Consumer Example
let ch = Channelint> { capacity: 3 }
let producer = spawn {
range(1, 4) |> forEach(fn(i) => send(ch, i))
}
let consumer = spawn {
range(1, 4) |> forEach(fn(i) => match recv(ch) {
Success { value } => print("got ${value}")
Error { message } => print("recv error: ${message}")
})
}
await(producer)
await(consumer)
select (planned)
select waits on multiple channel operations and runs the arm whose operation completes first:
selectExpr ::= "select" "{" selectArm+ "}"
selectArm ::= IDENT "=>" channelOp "=>" expr
| "_" "=>" expr (* timeout / default *)
let ch1 = Channelstring> { capacity: 1 }
let ch2 = Channelint> { capacity: 1 }
select {
msg => recv(ch1) => processString(msg)
num => recv(ch2) => processNumber(num)
_ => timeoutHandler()
}
Fiber-Isolated Modules (planned)
Each fiber that touches a module receives its own private instance. There is no shared mutable state across fibers; communication is via channels.
module Counter {
mut count = 0
fn increment() -> int = { count = count + 1; count }
fn get() -> int = count
}
let f1 = spawn Counter.increment() // 1
let f2 = spawn Counter.increment() // 1, not 2 — separate instance
await(f1)
await(f2)
A fiber's module instance is initialised on first access (copy-on-first-access) and is destroyed with the fiber.