Chapter 5 Results and errors
5
Chapter 5

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.

src/parse.slk
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.

src/parse.slk
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.

src/parse.slk
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.

Terminal
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.
  • match forced the caller to name both result cases.
  • error OutOfRange declared a contract error shape.
  • -> int | OutOfRange made 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