std::env
What a program was told: its arguments and its environment.
The smallest thing that separates a program from a demo. Until this existed, nothing a Khora program did could depend on anything outside its own source — every path, every port, every setting was compiled in.
The Clock capability is in std::clock, not here. This file is
native-only for getenv and argv; a clock has no such constraint, and
grouping the two would have imposed one for a reason that has nothing to do
with clocks.
The C side is almost all ISO C: getenv, strlen, memcpy. The one
exception is the argument vector, which no C function returns — it arrives
through main and is gone, so the generated main hands it to the runtime
and khora_arg gives it back.
API at a glance
Section titled “API at a glance”Types: EnvError
Effects: Env
Methods: Env
Functions: variable_or
EnvError
Section titled “EnvError”derive(Show, Eq)pub type EnvError = | Denied(name: String);Why reading the environment did not work.
One case, because there is one way for it to fail that is not “no such
variable”: the manifest did not grant it. Not being set is None, which is
an answer rather than a failure.
Effects
Section titled “Effects”pub effect Env { variable: (String) -> Option<String> raises EnvError, arguments: () -> List<String>,}What the process was started with.
A capability rather than plain functions, for the reason every other one is:
a function that reads DATABASE_URL says so in its signature, and a test
can hand it something else. Reading the environment is exactly the kind of
hidden input that makes a program hard to test, and this is the seam.
variable
Section titled “variable”variable: (String) -> Option
The value of a variable, or None when it is not set.
raises because a denial is not None. A variable the manifest does
not grant is a different thing from one nobody set, and the fix is a line
in khora.toml rather than a line in a deployment script. Answering
None for both would send a reader to look at their environment for a
decision their own manifest made – the same reasoning IoError::Denied
records.
arguments
Section titled “arguments”arguments: () -> List
Everything the process was invoked with, the program’s own name first — the same convention C, Rust and Go all follow.
Methods
Section titled “Methods”impl Envpub fn real() -> EnvThe real environment.
Functions
Section titled “Functions”variable_or
Section titled “variable_or”pub fn variable_or(name: String, fallback: String) -> String with { env: Env } raises EnvErrorA variable, or a default when it is not set.
The shape almost every caller wants, written once here rather than as a
match at each of them.
The fallback is for “not set”, not for “not allowed”. A denial passes
through rather than quietly becoming the default: a program told it may not
read DATABASE_URL and silently given localhost is a program that starts
and does the wrong thing, which is worse than one that stops and says why.
import std::env::{Env, variable_or};
fn port() -> Int with { env: Env } raises EnvError { match Int::of_string(variable_or("PORT", "8080")!) { Option::Some(n) => n, Option::None => 8080, }}The ! is there because a denial is a failure rather than a missing
value, which is the distinction the paragraph above is about.
Khora 0.3.0built frombd964738afb6on 2026-10-17 20:41ZVersioningSecurityContributingReleasesSource