Skip to main content
Domain failures are nominal error types and Result values. Each variant has a name and payload in Go’s “errors as values” style.

Nominal errors

Declare named failure kinds with payloads:
Use them with ensure … or …:
Each error variant is a distinct type. Callers can branch on structure instead of parsing error strings.

Simple payload example

A minimal nominal error with one payload field:

Result types

Functions that can fail with typed errors return Result(Success, Failure). The failure side is constrained to the Error family today.
Ok and Err serve as discriminants for is / ensure. They are not yet general value constructors for building Result values at every call site.

Return inference and implicit returns

Forst infers a function’s return type from:
  • explicit return statements
  • ensure (often producing Result(S, Error) when no return type is declared)
  • the last expression in the function body when no return type is declared in the signature
When the last statement is an expression and the function has no declared return type, that expression’s value becomes the function return. Generated Go emits an explicit return for it.
Here f also returns Result(Int, Error); generated Go contains return g(). Explicit return is still fine (and clearer when intent is ambiguous):

Trailing calls and Go imports

This differs from Go statement semantics. A trailing call whose Go signature is (T, error) is typed in Forst as Result(T, Error) when its result is used — including as an implicit return:
With no declared return type, logAndReport returns Result(Int, Error), not void. To log for side effects only, use Forst println / print, or declare a void return on a Provider contract method.

Go interop

Forst folds Go’s (T, error) returns into Result(T, Error) at the boundary where wired. Generated Go uses idiomatic error returns. Your ops team still reads familiar code.

Generate client types

Nominal errors can emit tagged shapes in generated .d.ts as the TS story matures. Today, prefer forst generate and treat error payloads as evolving. See Generate client types.

Compared to Go error structs

In Go you might write:
Forst’s error Name { … } syntax makes the intent explicit: this is a failure variant, a dedicated type for a specific failure mode rather than a generic struct with an Error() method attached by convention.

Caveats

Nominal errors and Result are experimental. Check the roadmap before relying on edge cases in production.

Result failure side

The failure type parameter is constrained to the Error family today. Arbitrary non-Error failure types are not supported yet.

Ok and Err role

Ok and Err are discriminants for is and ensure. They are not general value constructors at every call site yet.

Implicit return trap

When a function has no declared return type, a trailing Go call that returns (T, error) can make the whole function return Result(T, Error). That includes fmt.Println and similar calls. Use println for void side effects, or declare an explicit return type.

Nominal errors incomplete

ensure only failure authoring, or LUB rules, and TypeScript _tag export are still maturing. Treat generated error payloads as evolving. See Generate client types § Caveats. For ensure x is Ok() narrowing limits, see Ensure and narrowing § Caveats.

Try it

From the Forst repository:

Ensure and narrowing

How ensure connects checks to control flow.