Skip to content

Processes

A function that receives messages declares them with receives. That mailbox is part of the function type and is invariant: a fn() receives Integer -> :ok is not a fn() receives String -> :ok, and Pid<Integer> is not a Pid<String>. receive is legal only inside a receiving function, and its patterns must cover the mailbox. gale_std.process.self is accepted only in a receiving function. The Pid message parameter must match that mailbox.

mod processes
alias gale_std.process
pub type Message =
| Ping(process.Pid<:pong>)
| Stop
fn loop() receives Message -> :ok {
receive {
Ping(reply_to) -> {
_ = process.send(reply_to, :pong)
loop()
}
Stop -> :ok
}
}
pub fn start() -> process.Pid<Message> {
process.spawn(fn() receives Message -> loop())
}
pub fn round_trip(server: process.Pid<Message>) receives :pong -> :pong {
reply_to = process.self()
_ = process.send(server, Ping(reply_to))
receive {
:pong -> :pong
}
}
pub fn widen(pid: gale_std.process.Pid<Integer>) -> gale_std.process.Pid<Term> {
pid
}

A receive pattern can pin a variable with ^name to match the value it held when the receive started. In this example, {^tag, value} selects a reply with the expected tag. The fallback {_, _} consumes replies with other tags and waits again; it does not leave those replies in the mailbox.

mod processes
alias gale_std.process
pub type Tagged =
| Ask(tag: process.Ref, reply_to: process.Pid<{process.Ref, Integer}>)
| Halt
fn tagged_loop(n: Integer) receives Tagged -> :ok {
receive {
Ask(tag, reply_to) -> {
_ = process.send(reply_to, {tag, n})
tagged_loop(n)
}
Halt -> :ok
}
}
fn await(tag: process.Ref) receives {process.Ref, Integer} -> Integer {
receive {
{^tag, value} -> value
{_, _} -> await(tag)
}
}
pub fn tagged_round_trip() receives {process.Ref, Integer} -> Integer {
server = process.spawn(fn() receives Tagged -> tagged_loop(7))
tag = process.make_ref()
_ = process.send(server, Ask(tag, process.self()))
value = await(tag)
_ = process.send(server, Halt)
value
}

gale_std.task wraps Elixir Task with an invariant handle. gale_std.ets gives named tables a phantom identity so :users and :sessions handles cannot be mixed. Both are stdlib, not extra syntax.