Effects and capabilities
In Xo, a function’s signature says what it can touch. The effects are net,
fs, clock, rand, env, proc, and stdio. A pub function declares
the ones it uses; one without a uses clause is pure.
effects/main.xo
pub fn banner(out: Stdio, name: Str) uses stdio {
out.println("== ${name} ==")
}
pub fn slugify(s: Str) -> Str {
s.trim().to_lower().replace(" ", "-")
}
fn main(os: Os) {
banner(os.stdio, slugify(" Hello World "))
}
test "banner prints the name" {
banner(os.stdio, "x")
expect(os.stdio.output()) == "== x ==\n"
}Output:
== hello-world ==
bannerdeclaresuses stdio;slugifydeclares nothing, so it cannot touch the outside world at all.- The authority itself is a value:
bannercan only print because it was handed aStdio. The only source of these capabilities ismain’sos, so a library cannot open a file or a socket unless someone gives it one. - In a
test,osholds fakes: an in memory filesystem, a virtual clock, a network that fails unless you register a handler, and captured output, asos.stdio.output()shows.
Forgetting to declare an effect is caught, with the call that performs it:
pub fn greet(out: Stdio, name: Str) {
out.println("hello, ${name}")
}
fn main(os: Os) { greet(os.stdio, "Ada") }xo check says:
main.xo:1:8: error XO0701: `greet` is pub with no `uses` clause, so it is pure, but performs `stdio`
note: main.xo:2:3: `Stdio.println` uses `stdio` here
1 module(s), 1 error(s), 0 warning(s)