template/pkg/result/doc.go
djmil e204e43e6e use panics as a default error reporting mechanism
- runtime.Goexit() has too much performance overhead, and should be used only under special conditions
- introduce build tags
2026-04-23 21:05:18 +00:00

57 lines
2.3 KiB
Go

// Package result provides a generic Expect[T] type for happy-path-oriented code.
//
// # Purpose
//
// result is a convenience tool for removing error-threading clutter from
// application logic. Instead of propagating (value, error) pairs through every
// frame, functions return Expect[T] and the caller unwraps at the boundary.
//
// # Layering rule
//
// Reusable library code (packages under pkg/) must only *return* Expect[T] —
// it must never call .Expect(), .Must(), or .Expectf() itself. Those methods
// exit the current goroutine via runtime.Goexit and are only safe inside a
// goroutine controlled by [Go] or [Run]. Calling them in a library takes
// control away from the caller and makes the package non-composable.
//
// The right split:
//
// - pkg/ functions: return Expect[T] or Expect[Nothing] — let the caller decide.
// - Application code (cmd/, HTTP handlers, …): chain .Expect() calls freely,
// protected by a defer result.Catch(&err) or a result.Run wrapper.
//
// # Intended pattern
//
// 1. Deep call stacks write for the happy path, using [Expect.Expect] or
// [Expect.Expectf] to unwrap values — exiting the goroutine on failure
// (panic by default; runtime.Goexit with -tags result_goexit) rather than
// threading error returns through every frame.
// 2. The entry point wraps the work with [Go] or [Run], which spawn the work
// in a goroutine and collect any failure as a normal Go error.
//
// Stack traces are captured at the failure site and can be retrieved from the
// collected error via [StackTrace].
//
// # Constructors
//
// Use [Ok] to wrap a success value, [Fail] to wrap an error, and [Of] to
// bridge existing (value, error) return signatures:
//
// data := result.Of(os.ReadFile("cfg.json")).Expect("read config")
//
// # Boundary pattern
//
// func run() error {
// return result.Run(func() {
// port := parsePort(cfg.Port).Expect("load config port")
// _ = port // happy path continues …
// })
// }
//
// [Go] is the typed variant — it returns Expect[T] when the closure produces
// a value. [Run] is a convenience wrapper for closures that return nothing.
//
// Genuine runtime panics (nil-pointer dereferences, index out of bounds, etc.)
// are not recovered — they still crash the program, as they should.
package result