Effects
A function without a uses clause is guaranteed pure by the compiler. This
is not a coding convention and not the result of a review — it is a
consequence of analysing effects across the call graph. A function that
declares nothing has an empty capability set, and the empty set can never
contain the effect set of a function it calls.
The nine effects
Section titled “The nine effects”| Effect | What it grants | In the uses IO blanket? |
|---|---|---|
IO |
Console output, stdin | Yes |
Fs |
Filesystem | Yes |
Clock |
Clock and sleep | Yes |
Args |
Command line | Yes |
Exit |
Process termination | Yes |
Net |
DNS, sockets, TLS | No |
Rand |
Randomness | No |
Proc |
Child processes, environment | No |
Conc |
Tasks, channels, scheduling | No |
uses IO is a blanket alias: at parse time it expands to
{IO, Fs, Clock, Args, Exit}. It exists for backward compatibility with
older code. It does not cover Net, Rand, Proc or Conc — those
four must be declared explicitly.
Writing uses Bogus is a parse error, and the compiler lists the exact set of
valid effects.
Declaring an effect
Section titled “Declaring an effect”fn read_config(path: str) -> str uses Fs { return read_file(path)}
fn elapsed_ms() -> int uses Clock { return clock_ms()}
fn program_args() -> list[str] uses Args { return args()}
fn pure_compute(n: int) -> int { # No uses clause -> pure by default let mut s: int = 0 let mut i: int = 0 while i < n { s = s + i i = i + 1 } return s}pure_compute cannot print, cannot read a file, cannot read the clock and
cannot touch the network — and that is checked, not promised.
What the compiler says when you get it wrong
Section titled “What the compiler says when you get it wrong”When a declaration is missing, the compiler does not merely point at the offending line. It names the call chain that carried the effect in:
error: function 'load_config' calls 'read_file' which requires effect 'Fs'not declared (declared: (none - pure); missing: Fs)And if you declare pure but call something effectful:
error: function 'f' is declared 'pure' but calls 'println' which requireseffect 'IO' (declared pure but callee chain is not pure)pure and uses are mutually exclusive at parse time. pure is not
decoration: it is a claim that the checker verifies across the call graph
and names the offending edge when the claim is false.
The audit report
Section titled “The audit report”hlc --audit examples/effects_demo.hlsprints, for every function, the capabilities it declared next to the ones the compiler computed:
function declared computed ------------------------------ ------------------------------ ------ pure_compute (none - pure) (none) read_config Fs Fs elapsed_ms Clock Clock program_args Args Args main IO, Fs, Clock, Args, Exit IO, Fs, Clock, Args, ExitThe empty computed column for pure_compute is the argument in one line:
the compiler walked the call graph and found no effect at all.
Note that main’s declared column already shows the expanded blanket —
IO, Fs, Clock, Args, Exit — because the expansion happens at parse time.
Capability tokens
Section titled “Capability tokens”From Stage 111 an effect also has a value form, Cap[E] — a capability token
that can be bound, passed, returned and stored in a struct field. It can only
be issued by main or by a function that already declares that effect.
Checking a claim quickly
Section titled “Checking a claim quickly”| Question | Where to look |
|---|---|
| Can this function print? | Is IO in the computed column? |
| Can it touch the clock? | Is Clock in computed? |
| Can it open a socket? | Is Net in computed — even five call layers down? |
| Can it spawn a task? | Is Conc in computed? |
The full list of builtins per effect is in the quick reference.