Module

pooka/otp

src/pooka/otp.pooka

Typed letters, fresh identities, and the small handles that survive a restart. A Subject carries checked send and receive capabilities. Its native mailbox representation never pretends to be a Pooka class. Names and keys are fresh: their text is a label, not a lookup token. Create one at startup and pass it to the children that share it. Repeating name("clock") makes another name.

Pooka
let inbox: otp.Subject(String) = otp.new_subject()
otp.send(inbox, "hello")
assert otp.receive(inbox, 100) == Some("hello")

API reference

class

Subject

src/pooka/otp.pooka:19
class Subject(m)

Send and receive capabilities over one message type. Only private children construct these values. Receiving is restricted to the owning process.

class

Timer

src/pooka/otp.pooka:32
class Timer

A cancellable scheduled delivery. A successful cancellation prevents delivery; False means it already fired or was cancelled. A delivered message is not removed.

class

Name

src/pooka/otp.pooka:37
class Name(m)

A fresh server identity. Labels do not establish equality or a message type.

class

Key

src/pooka/otp.pooka:48
class Key(v)

A fresh typed storage capability. Equal labels never share a storage slot.

class

CallError

src/pooka/otp.pooka:55
class CallError

Why a request received no answer.

class

Timeout

src/pooka/otp.pooka:57
class Timeout is CallError
class

Down

src/pooka/otp.pooka:59
class Down(reason: String) is CallError
field

reason

src/pooka/otp.pooka:59
reason: String
INFERREDString
constructor

new

src/pooka/otp.pooka:59
INFERREDfn(String) -> pooka/otp.Down
enum

LogLevel

src/pooka/otp.pooka:62
enum LogLevel

Node-wide Erlang logger verbosity.

variant

Debug

src/pooka/otp.pooka:63
LogLevel.Debug
variant

Info

src/pooka/otp.pooka:64
LogLevel.Info
variant

Notice

src/pooka/otp.pooka:65
LogLevel.Notice
variant

Warning

src/pooka/otp.pooka:66
LogLevel.Warning
variant

Error

src/pooka/otp.pooka:67
LogLevel.Error
variant

Critical

src/pooka/otp.pooka:68
LogLevel.Critical
function

me

src/pooka/otp.pooka:126
me() -> Pid
INFERREDfn() -> Pid

The current BEAM process.

function

spawn

src/pooka/otp.pooka:131
spawn(work: fn() -> Nil) -> Pid
INFERREDfn(fn() -> Nil) -> Pid

Start an unlinked process; completion and failure remain local to it.

function

spawn_link

src/pooka/otp.pooka:136
spawn_link(work: fn() -> Nil) -> Pid
INFERREDfn(fn() -> Nil) -> Pid

Start a linked process. An abnormal exit propagates over the link.

function

is_alive

src/pooka/otp.pooka:141
is_alive(pid: Pid) -> Bool
INFERREDfn(Pid) -> Bool

Ask whether a local process is running now; it may stop immediately afterwards.

function

kill

src/pooka/otp.pooka:146
kill(pid: Pid) -> Nil
INFERREDfn(Pid) -> Nil

Stop a process without giving it an opportunity to run cleanup.

function

sleep

src/pooka/otp.pooka:151
sleep(milliseconds: Int) -> Nil
INFERREDfn(Int) -> Nil

Sleep for a nonnegative millisecond duration; negative values clamp to zero.

function

sleep_forever

src/pooka/otp.pooka:156
sleep_forever() -> Nil
INFERREDfn() -> Nil

Wait indefinitely, usually after starting a long-running application.

function

actor_pid

src/pooka/otp.pooka:161
actor_pid(handle: a) -> Option(Pid)
INFERREDfn(a) -> Option(Pid)

Inspect the checked native actor handle. Other values return None.

function

make_subject

src/pooka/otp.pooka:167
make_subject(
  post: fn(m) -> Nil,
  read: fn(Int) -> Option(m),
  wait: fn() -> m,
  owner: fn() -> Option(Pid),
  later: fn(Int, m) -> Timer,
  request: fn(Pid, m) -> Nil
) -> Subject(m)
INFERREDfn(fn(a) -> Nil, fn(Int) -> Option(a), fn() -> a, fn() -> Option(Pid), fn(Int, a) -> pooka/otp.Timer, fn(Pid, a) -> Nil) -> pooka/otp.Subject(a)

Typed capability constructor for Erlang adapters. The functions themselves preserve m; no arbitrary term is reinterpreted as a Subject.

function

make_timer

src/pooka/otp.pooka:179
make_timer(cancel: fn() -> Bool, remaining: fn() -> Option(Int)) -> Timer
INFERREDfn(fn() -> Bool, fn() -> Option(Int)) -> pooka/otp.Timer

Typed timer constructor used by adapters, normally reached through schedule.

function

new_subject

src/pooka/otp.pooka:184
new_subject() -> Subject(m)
INFERREDfn() -> pooka/otp.Subject(a)

Create a mailbox owned by this process, with a fresh selective-receive tag.

function

owner

src/pooka/otp.pooka:189
owner(subject: Subject(m)) -> Option(Pid)
INFERREDfn(pooka/otp.Subject(a)) -> Option(Pid)

The live process receiving these messages, if any.

function

send

src/pooka/otp.pooka:196
send(subject: Subject(m), message: m) -> Nil
INFERREDfn(pooka/otp.Subject(a), a) -> Nil

Send without waiting. Sending to a stopped process deliberately loses the message.

function

schedule

src/pooka/otp.pooka:208
schedule(subject: Subject(m), milliseconds: Int, message: m) -> Timer
INFERREDfn(pooka/otp.Subject(a), Int, a) -> pooka/otp.Timer

Schedule delivery and return its cancellation handle. Negative delays clamp to zero.

Pooka
let timer = otp.schedule(inbox, 1000, "wake up")
assert otp.cancel(timer)
function

send_after

src/pooka/otp.pooka:215
send_after(subject: Subject(m), milliseconds: Int, message: m) -> Nil
INFERREDfn(pooka/otp.Subject(a), Int, a) -> Nil

Schedule a delivery when the caller does not need a cancellation handle.

function

cancel

src/pooka/otp.pooka:221
cancel(timer: Timer) -> Bool
INFERREDfn(pooka/otp.Timer) -> Bool

Cancel a pending timer. Already delivered messages remain in the mailbox.

function

remaining

src/pooka/otp.pooka:228
remaining(timer: Timer) -> Option(Int)
INFERREDfn(pooka/otp.Timer) -> Option(Int)

Remaining milliseconds, or None after cancellation or delivery.

function

receive

src/pooka/otp.pooka:236
receive(subject: Subject(m), timeout: Int) -> Option(m)
INFERREDfn(pooka/otp.Subject(a), Int) -> Option(a)

Receive from a mailbox owned by this process. Other ownership is a runtime error; casts and reply-only subjects cannot be read through this function.

function

receive_forever

src/pooka/otp.pooka:243
receive_forever(subject: Subject(m)) -> m
INFERREDfn(pooka/otp.Subject(a)) -> a

Receive without a deadline, subject to the same ownership rule.

function

call

src/pooka/otp.pooka:251
call(subject: Subject(m), make: fn(Subject(r)) -> m, timeout: Int) -> Result(
  r,
  CallError
)
INFERREDfn(pooka/otp.Subject(a), fn(pooka/otp.Subject(b)) -> a, Int) -> Result(b, pooka/otp.CallError)

Make a request with a revocable reply alias. Late responses after a timeout are dropped before reaching the mailbox. The request builder runs in the caller.

function

describe

src/pooka/otp.pooka:273
describe(problem: CallError) -> String
INFERREDfn(pooka/otp.CallError) -> String

Describe a failed request without discarding the original typed error.

function

name

src/pooka/otp.pooka:287
name(label: String) -> Name(m)
INFERREDfn(String) -> pooka/otp.Name(a)

Allocate a fresh named-server identity. Keep this value across restarts.

Pooka
let left: otp.Name(Int) = otp.name("clock")
let right: otp.Name(String) = otp.name("clock")
// Equal labels, separate addresses and separate message types.
function

name_id

src/pooka/otp.pooka:293
name_id(name: Name(m)) -> String
INFERREDfn(pooka/otp.Name(a)) -> String

An adapter's binary registry token. name always creates a fresh identity; there is deliberately no inverse function that claims an arbitrary type.

function

key

src/pooka/otp.pooka:300
key(label: String) -> Key(v)
INFERREDfn(String) -> pooka/otp.Key(a)

Allocate a fresh persistent storage capability. The label never participates in lookup.

function

put

src/pooka/otp.pooka:306
put(key: Key(v), value: v) -> Nil
INFERREDfn(pooka/otp.Key(a), a) -> Nil

Store under this capability, replacing its previous value.

function

get

src/pooka/otp.pooka:313
get(key: Key(v)) -> Option(v)
INFERREDfn(pooka/otp.Key(a)) -> Option(a)

Read the value belonging to this exact capability.

function

erase

src/pooka/otp.pooka:320
erase(key: Key(v)) -> Nil
INFERREDfn(pooka/otp.Key(a)) -> Nil

Release persistent storage. Existing holders can still store a new value.

function

set_log_level

src/pooka/otp.pooka:327
set_log_level(level: LogLevel) -> Nil
INFERREDfn(pooka/otp.LogLevel) -> Nil

Change logging for the whole node, not just the calling process.

class

ProcessDown

src/pooka/otp.pooka:332
class ProcessDown(pid: Pid, reason: String)

A process exit, keeping both the identity and its printable reason.

field

pid

src/pooka/otp.pooka:332
pid: Pid
INFERREDPid
field

reason

src/pooka/otp.pooka:332
reason: String
INFERREDString
constructor

new

src/pooka/otp.pooka:332
INFERREDfn(Pid, String) -> pooka/otp.ProcessDown
class

Monitor

src/pooka/otp.pooka:335
class Monitor

An owner-bound monitor. It observes exits without linking process lifetimes.

function

monitor

src/pooka/otp.pooka:359
monitor(pid: Pid) -> Monitor
INFERREDfn(Pid) -> pooka/otp.Monitor

Watch a process without receiving its exit as a failure of this process.

Pooka
let watch = otp.monitor(worker)
otp.kill(worker)
let assert Some(stopped) = otp.wait_down(watch, 1000)
assert stopped.pid == worker
function

wait_down

src/pooka/otp.pooka:364
wait_down(watch: Monitor, timeout: Int) -> Option(ProcessDown)
INFERREDfn(pooka/otp.Monitor, Int) -> Option(pooka/otp.ProcessDown)

Wait for this monitor's DOWN notification; other mailbox messages stay put.

function

demonitor

src/pooka/otp.pooka:371
demonitor(watch: Monitor) -> Bool
INFERREDfn(pooka/otp.Monitor) -> Bool

Remove a monitor and flush its own pending notification, not unrelated ones.

function

link

src/pooka/otp.pooka:378
link(pid: Pid) -> Nil
INFERREDfn(Pid) -> Nil

Link local process lifetimes. Abnormal exits propagate unless trapped.

function

unlink

src/pooka/otp.pooka:383
unlink(pid: Pid) -> Nil
INFERREDfn(Pid) -> Nil

Remove a link without stopping either process.

function

mailbox_size

src/pooka/otp.pooka:398
mailbox_size() -> Int
INFERREDfn() -> Int

Count this process's queued messages. Useful for observing backpressure.

function

trap_exits

src/pooka/otp.pooka:404
trap_exits(enabled: Bool) -> Bool
INFERREDfn(Bool) -> Bool

Change exit trapping, returning its previous value. Linking is a lifecycle decision: callers that enable trapping must handle the resulting exit messages.

function

receive_exit

src/pooka/otp.pooka:409
receive_exit(timeout: Int) -> Option(ProcessDown)
INFERREDfn(Int) -> Option(pooka/otp.ProcessDown)

Read one trapped link exit. Monitor DOWN notifications are separate.