Events
An event declares a broadcast channel: one emit and every subscriber receives the payload in turn. An event can live at module top level or on a type, where it becomes an instance event.
Declaring and Emitting
event Ticked(n: int);
event Ping();The payload is a positional parameter list; emit channel(args); fires the event. Subscribe with ~>, unsubscribe with !~> (safe even when not subscribed):
event Ticked(n: int);
func OnTick(n: int)
{
print("tick", n);
}
func OnTick2(n: int)
{
print("tick2", n);
}
Ticked ~> OnTick;
Ticked ~> OnTick2;
emit Ticked(5);
Ticked !~> OnTick2;
emit Ticked(6);tick 5
tick2 5
tick 6After unsubscribing, one subscriber remains. <~ is the same subscription written the other way round (OnPing <~ Ping; equals Ping ~> OnPing), matching the reading order “the consumer subscribes”.
Dispatch Order and Deduplication
Dispatch follows subscription order (first subscribed, first dispatched) and completes synchronously: handlers run one by one inside emit’s call stack, regardless of declaration order:
event Ticked(n: int);
Ticked ~> (n: int) => print("h2", n);
Ticked ~> (n: int) => print("h1", n);
Ticked ~> (n: int) => print("h3", n);
emit Ticked(1);h2 1
h1 1
h3 1Subscribing the same handler to the same event more than once deduplicates: it takes one slot and dispatches once, and a single !~> removes it completely.
Reentrancy
Emitting again while a handler runs (the same event or another) is legal: the inner emit dispatches recursively right away, nesting like the call stack, and the outer level continues only after the inner one has fully finished. Unsubscribing yourself mid-dispatch does not affect the current round; from the next round on, you stop receiving:
event A(n: int);
A ~> (n: int) =>
{
print("enter", n);
if n < 2
{
emit A(n + 1);
}
print("exit", n);
};
emit A(1);enter 1
enter 2
exit 2
exit 1Handler Shapes
A handler can be a named function or a lambda. The return type is unconstrained; declaring -> int is legal and the return value is ignored.
A subscribed handler must be a plain function: no fail, no uses, not async.
Instance Events
An event declared on a class is an instance event; the dispatch table is isolated per instance:
class Counter
{
public event Changed(from: int, to: int);
public var value: int = 0;
public func Set(v: int)
{
val old = value;
value = v;
emit Changed(old, v);
}
}
func OnCh(from: int, to: int)
{
print("chg", from, "->", to);
}
val g = new Counter();
g.Changed ~> OnCh;
g.Set(1);
g.Changed !~> OnCh;
g.Set(2);chg 0 -> 1Unsubscribing from an instance event, g.Changed !~> h, works the same as at top level. Whether a subscription dies automatically after the instance drops its last reference is up to the host GC — the language makes no promise, and the handle’s IsCancelled does not become True because of it.
Event Props
An event prop (event prop) goes a step further: writing is broadcasting. The payload is fixed at (old, new) and a change check is built in — the second = 5 produces no broadcast:
class Gauge
{
public event prop Level: int;
}
val g = new Gauge();
g.Level ~> (oldV: int, newV: int) => { print($"level {oldV} -> {newV}"); };
g.Level = 5;
g.Level = 5;
g.Level = 8;level 0 -> 5
level 5 -> 8The change check happens after the before segment rewrites the value. A same-value write skips the entire write chain — storage, the after segment, and the automatic emit are all skipped; only finally always runs, with or without subscribers (pipeline segment syntax: Event Pipelines).
Generic Events
event Changed<T>(v: T); can only be declared at top level; each instantiation is a channel. Type arguments can be inferred three ways: explicit instantiation (Changed<int> ~> onInt), from the handler’s parameters (Changed ~> (v: int) => ...), or from the emit arguments (emit Changed(43);).
Different instantiations are different channels: a subscriber of Changed<int> never receives emit Changed("s"). The two channels are fully separate, and nothing errors.
Notes
- Events are also an operand of
await:await <event source>waits once for the next firing and returns the payload. See Awaiting Events. - Events carry before / after / finally pipeline segments and the eight-step write sequence. See Event Pipelines.
- For the
subscriptionhandle a subscription produces, see Subscription Handles and Event Values.
