Results and errors
Silk separates two ideas that are often blurred together: recoverable failures are values, while typed errors describe contract violations that must be declared.
Use Result for recoverable failure
If the caller can continue normally, return data that describes success or failure.
package parse;
type PortResult = Result(int, string);
fn parse_port (text: string) -> PortResult {
if text == "" {
return Err("port is required");
}
if text == "8080" {
return Ok(8080);
}
return Err("unsupported port");
}
Handle both cases
A result keeps the caller honest because the failure value is part of the type.
fn port_or_default (text: string) -> int {
match (parse_port(text)) {
PortResult::Ok(port) => {
return port;
},
PortResult::Err(_) => {
return 3000;
},
}
}
Declare contract errors separately
Typed errors use error, panic, and a declared error contract.
error OutOfRange {
value: int,
}
fn require_user_port (port: int) -> int | OutOfRange {
if port < 1024 {
panic OutOfRange { value: port };
}
return port;
}
Check the contract
The compiler verifies that typed errors are declared and handled according to their signatures.
silk check src/parse.slk
silk test src/parse.slk
Use Result(T, E) for recoverable domain outcomes. Use typed errors for broken contracts
that should not continue as ordinary control flow.
What changed
Result(int, string)carried recoverable parse failure.matchforced the caller to name both result cases.error OutOfRangedeclared a contract error shape.-> int | OutOfRangemade the typed error contract visible.
Chapter complete
You now have the core Silk learning path. Continue into the docs for structs, interfaces, testing, ABI, and Formal Silk.
Continue in docs