Effects
Why This Matters
Effects tell the compiler what side effects a function is allowed to perform. This turns hidden runtime behavior into explicit compile-time contracts.
Attribute Reference
@Pure: function must remain side-effect free@Io: allows I/O side effects@Thread: allows thread/time side effects@Net: marks network-effect capability@Alloc: marks allocation-effect capability@Unsafe: marks unsafe-effect capability@Any: allow any effects (escape hatch)
Minimal Example
import std.io.*;
@Pure
function add(a: Integer, b: Integer): Integer {
return a + b;
}
@Io
function logLine(msg: String): None {
println(msg);
return None;
}
Compiler Rules
@Pure
- cannot call effectful functions
- cannot be combined with explicit effects (
@Io,@Thread, ...) - cannot be combined with
@Any
@Any
- allows calling functions across mixed effect categories
- caller must also be
@Anywhen invoking an@Anycallee @Pureor narrowly-annotated callers cannot call@Anydirectly
Explicit effect enforcement
If a function calls another function requiring an effect, caller must declare that effect (or use @Any).
import std.io.*;
@Io
function writeLog(): None {
println("log");
return None;
}
Without @Io, this call is rejected during type checking.
Effect propagation is transitive across wrappers.
@Net
function netCall(): None {
return None;
}
function wrapper(): None {
netCall();
return None;
}
@Io
function caller(): None {
wrapper(); // compile-time error: Missing effect 'net'
return None;
}
@Io on the top-level caller does not satisfy a transitive @Net requirement.
Inference
If you omit effect attributes, compiler infers effects from function body and call graph.
Practical recommendation:
- explicit effects on public APIs
- inference for internal helpers when that improves readability
Built-in Calls and Required Effects
Current built-in behavior in compiler checks:
println,print,read_line,File.*,System.*,Args.*-> requireioTime.sleep,Time.now,Time.unix-> requirethread
std.net Namespace Status
import std.net.*; is valid now, but stdlib currently exposes no runtime
Net.* API members yet.
Practical meaning:
- effect contracts like
@Netare enforced by type checking - avoid documenting/expecting non-existent
Net.*runtime functions
Important distinction:
@Netanswers: "is this function allowed to perform network effect category work?"std.netanswers: "what runtime network API surface is currently exposed?"
Today, the first exists (effect checking), the second is placeholder-only.
@Any Usage Rule
@Any is useful for boundary/orchestrator functions that intentionally mix effect categories.
Do not overuse it in core logic, or you lose effect-level guarantees.
Common Mistakes
- adding
@Pureand then callingprintln - forgetting to propagate required effect to caller
- overusing
@Anywhere narrow effects would be clearer