LEVIATHAN v962456e · 962456eee1

Library

Capability interfaces

IEnv, IConsole, IClock, IFileSystem and INet: injectable stand-ins for the ambient environment, console, clock, files and network.

since 0.1.0-alpha.1linuxwindowswasm

Description

The standard library offers five small interfaces, one for each way a program normally reaches the outside world. Each is an alternative to an ambient global: instead of reading env::args() or calling console.writeln directly, a function can ask for the capability as a parameter and let dependency injection (bind and inject) fill it in.

Interface What it offers The ambient equivalent
IEnv args(), variable(name) (None when unset) env::args(), env::get(name)
IConsole write(s), writeln(s), writeln() console
IClock now(), milliseconds since the epoch the system clock
IFileSystem open(path, mode) returning a File, exists(path) File, std::fileExists
INet connect(host, port) returning TcpStream? (None on failure), listen(port) returning a TcpListener TcpStream, TcpListener

Each has one real implementation, a small stateless class that forwards to the ambient surface: SystemEnv, SystemConsole, SystemClock, SystemFileSystem and SystemNet. Because they are the only implementation underneath, injected code and ambient code behave identically.

All five are in the std namespace, so the names are visible everywhere. Visibility is not provision: nothing is bound just because a name is visible. The real implementation of a capability is activated only by an explicit use std::IClock; (and so on), which installs the standard binding for that interface into the scope where the use is written. An explicit bind of your own, written closer to the call, always wins, which is how you substitute a fake.

Injecting a fake clock

use std::IConsole;
use std::IClock;

class FakeClock : IClock {
    int ms;
    new FakeClock(int start) { ms = start; }
    int now() {
        ms += 250;
        return ms;
    }
}

int elapsed(IClock clock, IConsole out) {
    int start = clock.now();
    out.writeln("started at ${start}");
    int end = clock.now();
    out.writeln("finished at ${end}");
    return end - start;
}

void run() {
    bind IClock => FakeClock(1000);
    console.writeln("elapsed ${elapsed()} ms");
}
run();
started at 1250
finished at 1500
elapsed 250 ms

elapsed never mentions a concrete clock or console. The use lines provide the real console; the bind inside run replaces the clock with one that advances by 250 milliseconds on every call, so the output is the same on every run.

Rules

  • A capability is a claim, not an enforced sandbox. The ambient globals (console, env, File, and the rest) stay reachable from anywhere whatever a function signature says. The guarantee is that the disciplined path, taking one injected parameter, is cheaper than the ambient one; the compiler does not forbid the other.
  • A bind must enclose the call that needs it. Binding inside a function reaches only the calls made from inside that function.
  • IEnv.variable reads env::get: None means unset, which is different from set to an empty string.
  • INet.connect returns None when the connection fails, where a raw connection would report failure with a silent no-op write.
  • IFileSystem and INet control how a File, TcpStream or TcpListener is acquired; they hand back the real objects, and what those objects can do is unchanged.
  • The same implementation sits under both the injected and the ambient path.

Examples

See the program above for a fake clock. A fake IEnv is shown in std.env.

See also

  • IEnv — What a program may learn from the process environment: its arguments and its variables.
  • IConsole — What a program may say to the terminal.
  • IClock — What a program may know about the time.
  • IFileSystem — What a program may do with the file system: open files and check whether a path exists.
  • INet — What a program may do with the network: open connections and listen for them.
  • SystemEnv — The real process environment behind the IEnv interface.
  • SystemConsole — The real console behind the IConsole interface: it prints to standard output.
  • SystemClock — The real clock behind the IClock interface.
  • SystemFileSystem — The real file system behind the IFileSystem interface.
  • SystemNet — The real network behind the INet interface.
  • env — The running process: its command-line arguments, its environment variables, and how it exits.