Gotchas
A checklist of idioms that trip people up — each with the working shape. Grown as findings land (the backlog’s “idiom traps”, promoted here).
Arriving with an error message in hand? The error index is organized by message instead of by topic.
Language
- Chained element access on a call result loses the element type.
shared.read()[i]→ bind, then index:let list = shared.read(); list[i]. matchcan’t be an operator operand.(match x { … }) + 1→ bind the match to a local first.- A bare integer literal adapts to its peer; two typed variables
don’t.
stamp + 1000andstamp < 1000are fine on ani53(the literal takes the peer’s type), but mixing two differently-typed variables in a comparison is an error — there are no implicit conversions; convert withas_*or unify the declarations.
Reactive & UI
shared.read()is a copy —shared.read().push(x)is lost; write through the cell:shared.write().push(x).- Mutate signal lists with
set_with, never by mutating aget()result (also a copy). bind_valuefights remote updates — for server-backed fields usebind_draft.showkeeps bindings live while hidden; usewhento drop state and subscriptions.- Disposal doesn’t cancel the in-flight wave: a subscriber already queued in the draining turn may fire once more; only later deliveries are guaranteed gone.
Services & the wire
- Contract-mismatch errors on connect usually mean a leaked old server
still holding the port —
ss -tlnp | grep <port>, kill by PID. descis an SQL keyword — name the columndescription(any SQL keyword as a column name fails inCREATE TABLE).- Value semantics cross the wire: a mirrored list is a fresh copy per update; mutate via rpcs, never by writing the client’s mirror signal.
Process & testing
- A completed node
mainexits the process — long-lived clients/servers must holdmainopen. pkill -f <pattern>can match your own shell’s command string — kill by tracked PID.- Rebuild the debug binary before regenerating corpus goldens — a stale binary silently writes wrong goldens.