option

package
v0.41.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 15, 2026 License: MIT Imports: 6 Imported by: 0

README

option

Optional values that make absence explicit in the type.

Option[T] stores a value plus an ok flag. The zero value is not-ok, so it works without initialization.

// Before: four lines to extract a map value with a default
token, ok := headers["Authorization"]
if !ok {
    token = "none"
}

// After
token := option.Lookup(headers, "Authorization").Or("none")

Four lines become one.

What It Looks Like

// Environment with default
port := option.Env("PORT").Or("8080")
// Conditional pipeline
name := userOption.KeepIf(User.IsActive).ToString(User.Name).Or("unknown")
// Comma-ok extraction
if user, ok := userOption.Get(); ok {
    fmt.Println(user.Name())
}
// Side effect — fires only if ok
userOption.IfOk(User.Save)
// Before: three separate absence checks, then assemble
host := record.RawHost()
if host == "" {
    host = "localhost"
}
port := os.Getenv("PORT")
if port == "" {
    port = "8080"
}
name, ok := labels["name"]
if !ok {
    name = "default"
}
return Config{Host: host, Port: port, Name: name}

// After: every field resolves inline
return Config{
    Host: record.Host().Or("localhost"),
    Port: option.Env("PORT").Or("8080"),
    Name: option.Lookup(labels, "name").Or("default"),
}
// Tri-state boolean — option.Bool is Option[bool]
type ScanResult struct {
    IsConnected option.Bool  // true, false, or unknown
}
connected := option.OrFalse(rslt.IsConnected)  // unknown → false
// Nullable field — return option instead of zero value
func (r Record) Host() option.String {
    return option.NonZero(r.host)
}
// Caller decides how to handle absence
addr := record.Host().Or("localhost")
// Pre-declared not-ok values read as intent in returns
func (db *DB) FindUser(id int) option.Int {
    row := db.QueryRow("SELECT id FROM users WHERE id = ?", id)
    var uid int
    if err := row.Scan(&uid); err != nil {
        return option.NotOkInt
    }
    return option.Of(uid)
}

One Type for All of Go's "Maybe" Patterns

Go represents absence three different ways: *T (nil), zero values ("", 0), and comma-ok returns (map lookup, type assertion). Each has a different failure mode — nil derefs panic, zero values are silently ambiguous, and ignored ok values lose the distinction between missing and present.

Option[T] unifies them. Factory functions bridge each Go pattern into a single chainable type:

  • NonNil(ptr) — pointer-based absence
  • NonZero(count), NonEmpty(name) — zero-value absence (use only when zero/empty truly means absent in your domain)
  • Lookup(m, key), New(val, ok) — comma-ok absence
  • When(cond, val), WhenCall(cond, fn) — conditional construction (eager/lazy)
  • Env("PORT") — environment variable absence (unset or empty)

Once you have an Option[T], the same API works regardless of where the value came from: .Or("default"), .KeepIf(valid), .ToString(format), .Get().

Operations

Option[T] holds an optional value — ok or not-ok. Type aliases String, Int, Bool, etc. are shorthand for common types, with pre-declared not-ok values (NotOkString, NotOkInt, etc.). JSON serialization via MarshalJSON/UnmarshalJSON (ok → value, not-ok → null). SQL via Value/Scan (ok → value, not-ok → NULL). Note: both JSON and SQL collapse Ok(nil) and NotOk into the same representation (null/NULL) — a round-trip through serialization may lose the distinction.

  • Create: Of, New, When, WhenCall, NotOk, NonZero, NonEmpty, NonNil, NonErr, Env, Lookup
  • Create + Transform: NonZeroCall, NonEmptyCall, NonNilCall — check presence and apply fn in one step
  • Extract: Get, IsOk, MustGet, Or, OrCall, OrElse, OrZero, OrEmpty, OrFalse (standalone for Option[bool])
  • Transform: Convert (same type), Map (cross-type, standalone), ToString, ToInt, other To*, ToOpt
  • Filter: KeepIf, RemoveIf
  • Side effects: IfOk, IfNotOk, Lift

See pkg.go.dev for complete API documentation, the main README for installation, Nil Safety in Go for the full discussion, and the showcase for real-world rewrites.

Documentation

Overview

Package option provides types and functions to work with optional values.

Option[T] holds a value plus an ok flag. The zero value is not-ok, so it works without initialization. Construct via Of, New, When, WhenCall, NonZero, NonEmpty, NonNil, or Env.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	NotOkAny    = Option[any]{}
	NotOkBool   = Option[bool]{}
	NotOkByte   = Option[byte]{}
	NotOkError  = Option[error]{}
	NotOkInt    = Option[int]{}
	NotOkRune   = Option[rune]{}
	NotOkString = Option[string]{}
)

Functions

func Lift added in v0.15.0

func Lift[T any](fn func(T)) func(Option[T])

Lift transforms a function operating on T into one operating on Option[T]. The lifted function executes only when the option is ok.

func OrFalse added in v0.41.0

func OrFalse(o Option[bool]) bool

OrFalse returns the option's value if ok, or false if not-ok. Standalone for type safety — Go methods cannot constrain T to bool.

Types

type Any

type Any = Option[any]

type Bool

type Bool = Option[bool]

type Byte

type Byte = Option[byte]

type Error

type Error = Option[error]

type Int

type Int = Option[int]

type Option added in v0.30.0

type Option[T any] struct {
	// contains filtered or unexported fields
}

Option represents an optional value of type T.

func FlatMap added in v0.41.0

func FlatMap[T, R any](b Option[T], fn func(T) Option[R]) (_ Option[R])

FlatMap returns the result of applying fn to the option's value if ok, or not-ok otherwise.

func Lookup added in v0.23.0

func Lookup[K comparable, V any](m map[K]V, key K) (_ Option[V])

Lookup returns an ok option of the value at key in m, or not-ok if the key is absent.

func Map

func Map[T, R any](b Option[T], fn func(T) R) (_ Option[R])

Map returns an option of the result of applying fn to the option's value if ok, or not-ok otherwise. For same-type mapping, use the Convert method.

func New

func New[T any](t T, ok bool) (_ Option[T])

New returns an ok option of t provided that ok is true, or not-ok otherwise. For condition-first construction, see When and WhenCall.

func NonEmptyCall added in v0.41.0

func NonEmptyCall[R any](s string, fn func(string) R) (_ Option[R])

NonEmptyCall returns an ok option of fn(s) provided that s is not empty, or not-ok otherwise. It is the string-specific variant of NonZeroCall.

func NonErr added in v0.41.0

func NonErr[T any](t T, err error) (_ Option[T])

NonErr returns an ok option of t provided that err is nil, or not-ok otherwise.

func NonNil added in v0.30.0

func NonNil[T any](t *T) (_ Option[T])

NonNil returns an ok option of *what t points at* provided that t is not nil, or not-ok otherwise. It converts a pointer-based pseudo-option (where nil means absent) into a formal option.

func NonNilCall added in v0.41.0

func NonNilCall[T any, R any](t *T, fn func(T) R) (_ Option[R])

NonNilCall returns an ok option of fn(*t) provided that t is not nil, or not-ok otherwise. It dereferences the pointer before passing to fn, matching NonNil's behavior.

func NonZero added in v0.30.0

func NonZero[T comparable](t T) (_ Option[T])

NonZero returns an ok option of t provided that t is not the zero value for T, or not-ok otherwise. Zero values include "" for strings, 0 for numbers, false for bools, etc.

func NonZeroCall added in v0.41.0

func NonZeroCall[T comparable, R any](t T, fn func(T) R) (_ Option[R])

NonZeroCall returns an ok option of fn(t) provided that t is not the zero value for T, or not-ok otherwise. It combines NonZero and a transform in one call — check presence and transform in a single step.

func NotOk

func NotOk[T any]() (_ Option[T])

NotOk returns a not-ok option of type T.

func Of

func Of[T any](t T) Option[T]

Of returns an ok option of t, independent of t's value.

func When added in v0.41.0

func When[T any](cond bool, t T) Option[T]

When returns an ok option of t if cond is true, or not-ok otherwise. It is the condition-first counterpart of New (which mirrors the comma-ok idiom).

Note: t is evaluated eagerly by Go's call semantics. For expensive computations that should only run when cond is true, use WhenCall.

Style guidance: prefer When for explicit boolean conditions. Prefer New when forwarding a comma-ok result (v, ok := m[k]).

Example
package main

import (
	"fmt"

	"github.com/binaryphile/fluentfp/option"
)

func main() {
	overdue := true
	level := option.When(overdue, "critical").Or("info")
	fmt.Println(level)

	overdue = false
	level = option.When(overdue, "critical").Or("info")
	fmt.Println(level)
}
Output:

critical
info

func WhenCall added in v0.41.0

func WhenCall[T any](cond bool, fn func() T) Option[T]

WhenCall returns an ok option of fn() if cond is true, or not-ok otherwise. The function is only called when the condition is true. Panics if fn is nil, even when cond is false.

Example
package main

import (
	"fmt"

	"github.com/binaryphile/fluentfp/option"
)

func main() {
	// fetchConfig is only called when needsFetch is true.
	fetchConfig := func() string { return "fetched" }

	result := option.WhenCall(true, fetchConfig).Or("default")
	fmt.Println(result)

	result = option.WhenCall(false, fetchConfig).Or("default")
	fmt.Println(result)
}
Output:

fetched
default

func ZipWith added in v0.41.0

func ZipWith[A, B, R any](a Option[A], b Option[B], fn func(A, B) R) (_ Option[R])

ZipWith returns an ok option of fn(a, b) if both options are ok, or not-ok otherwise.

func (Option[T]) Convert added in v0.30.0

func (b Option[T]) Convert(fn func(T) T) (_ Option[T])

Convert returns the result of applying fn to the option's value provided that the option is ok, or not-ok otherwise.

func (Option[T]) FlatMap added in v0.41.0

func (b Option[T]) FlatMap(fn func(T) Option[T]) (_ Option[T])

FlatMap returns the result of applying fn to the option's value if ok, or not-ok otherwise.

func (Option[T]) Get added in v0.30.0

func (b Option[T]) Get() (_ T, _ bool)

Get returns the option's value and a boolean indicating the option's status. It unpacks the option's fields into Go's comma-ok idiom, making it useful in the usual Go conditional constructs. When used in this manner, myVal doesn't stick around in the namespace when you're done with it:

if myVal, ok := o.Get; ok {
  do some stuff
}

func (Option[T]) IfNotOk added in v0.30.0

func (b Option[T]) IfNotOk(fn func())

IfNotOk calls fn if the option is not ok.

func (Option[T]) IfOk added in v0.30.0

func (b Option[T]) IfOk(fn func(T))

IfOk applies fn to the option's value provided that the option is ok.

func (Option[T]) IsOk added in v0.30.0

func (b Option[T]) IsOk() bool

IsOk returns true if the option is ok.

func (Option[T]) KeepIf added in v0.30.0

func (b Option[T]) KeepIf(fn func(T) bool) (_ Option[T])

KeepIf returns b provided that applying fn to an ok option's value returns true, or the original option otherwise. It is the filter operation. Since Go doesn't offer a convenient lambda syntax for constructing the negation of a function's output, there is a RemoveIf method as well.

func (Option[T]) MarshalJSON added in v0.30.0

func (o Option[T]) MarshalJSON() ([]byte, error)

MarshalJSON serializes Option: Ok(v) → json(v), NotOk → null. Note: Ok(nil) and NotOk both serialize to null — the receiver cannot distinguish them. If round-trip fidelity matters, wrap the value in a non-nil container before storing.

func (Option[T]) MustGet added in v0.30.0

func (b Option[T]) MustGet() T

MustGet returns the option's value or panics if the option is not ok.

func (Option[T]) Or added in v0.30.0

func (b Option[T]) Or(t T) T

Or returns the option's value provided that the option is ok, otherwise t. For an Option[T]-valued fallback that preserves optionality, see Option.OrElse.

func (Option[T]) OrCall added in v0.30.0

func (b Option[T]) OrCall(fn func() T) (_ T)

OrCall returns the option's value provided that it is ok, otherwise the result of calling fn. For an Option[T]-valued fallback, see Option.OrElse.

func (Option[T]) OrElse added in v0.41.0

func (b Option[T]) OrElse(fn func() Option[T]) (_ Option[T])

OrElse returns b if b is ok; otherwise it calls fn and returns its result. Unlike Option.Or and Option.OrCall which extract T, OrElse stays in Option[T] — enabling multi-level fallback chains:

user := envLookup("USER").
    OrElse(configLookup).
    OrElse(defaultUserOption).
    Or("unknown")

func (Option[T]) OrEmpty added in v0.30.0

func (b Option[T]) OrEmpty() (_ T)

OrEmpty returns the option's value provided that it is ok, otherwise the zero value for T. It is a more readable alias for OrZero when T is string.

func (Option[T]) OrWrap added in v0.41.0

func (b Option[T]) OrWrap(fn func() T) Option[T]

OrWrap returns the original option if ok, or an ok option of fn() if not-ok. Like Option.OrCall but stays in Option for further chaining. Like Option.OrElse but fn returns T (always wrapped as ok) rather than Option[T].

func (Option[T]) OrZero added in v0.30.0

func (b Option[T]) OrZero() (_ T)

OrZero returns the option's value provided that it is ok, otherwise the zero value for T.

func (Option[T]) RemoveIf added in v0.30.0

func (b Option[T]) RemoveIf(fn func(T) bool) (_ Option[T])

RemoveIf returns a not-ok option provided that applying fn to an ok option's value returns true, or the original option otherwise. It is the filter operation with negation. Since Go doesn't offer a convenient lambda syntax for constructing the negation of a function's output, having negation built-in is both a convenience and keeps consuming code readable.

func (*Option[T]) Scan added in v0.41.0

func (o *Option[T]) Scan(src any) error

Scan implements sql.Scanner: nil → NotOk, value → Ok with type conversion.

func (Option[T]) ToAny added in v0.30.0

func (b Option[T]) ToAny(fn func(T) any) (_ Option[any])

ToAny returns an option of the result of applying fn to the option's value provided that the option is ok, or not-ok otherwise.

func (Option[T]) ToBool added in v0.30.0

func (b Option[T]) ToBool(fn func(T) bool) (_ Option[bool])

ToBool returns an option of the result of applying fn to the option's value provided that the option is ok, or not-ok otherwise.

func (Option[T]) ToByte added in v0.30.0

func (b Option[T]) ToByte(fn func(T) byte) (_ Option[byte])

ToByte returns an option of the result of applying fn to the option's value provided that the option is ok, or not-ok otherwise.

func (Option[T]) ToError added in v0.30.0

func (b Option[T]) ToError(fn func(T) error) (_ Option[error])

ToError returns an option of the result of applying fn to the option's value provided that the option is ok, or not-ok otherwise.

func (Option[T]) ToInt added in v0.30.0

func (b Option[T]) ToInt(fn func(T) int) (_ Option[int])

ToInt returns an option of the result of applying fn to the option's value provided that the option is ok, or not-ok otherwise.

func (Option[T]) ToOpt added in v0.30.0

func (b Option[T]) ToOpt() (_ *T)

ToOpt returns a pointer to a copy of the value if ok, or nil if not-ok. The returned pointer does not alias the Option's internal storage. By convention, in consuming code, we suffix a pseudo-option's variable name with an "Opt" suffix to clarify the pointer's meaning and use, hence "ToOpt".

func (Option[T]) ToRune added in v0.30.0

func (b Option[T]) ToRune(fn func(T) rune) (_ Option[rune])

ToRune returns an option of the result of applying fn to the option's value provided that the option is ok, or not-ok otherwise.

func (Option[T]) ToString added in v0.30.0

func (b Option[T]) ToString(fn func(T) string) (_ Option[string])

ToString returns an option of the result of applying fn to the option's value provided that the option is ok, or not-ok otherwise.

func (*Option[T]) UnmarshalJSON added in v0.30.0

func (o *Option[T]) UnmarshalJSON(data []byte) error

UnmarshalJSON deserializes Option: null → NotOk, value → Ok(value). Note: because JSON null becomes NotOk, a round-trip through Ok(nil) → JSON → unmarshal yields NotOk, not Ok(nil). This is intentional — null means absent.

func (Option[T]) Value added in v0.41.0

func (o Option[T]) Value() (driver.Value, error)

Value implements driver.Valuer: Ok(v) → v, NotOk → nil. Note: Ok with a nil-typed value and NotOk both produce SQL NULL — the database cannot distinguish them.

type Rune

type Rune = Option[rune]

type String

type String = Option[string]

func Env added in v0.41.0

func Env(key string) String

Env returns an ok option of the environment variable's value if set and non-empty, or not-ok if unset or empty.

func NonEmpty added in v0.30.0

func NonEmpty(s string) (_ String)

NonEmpty returns an ok option of s provided that s is not empty, or not-ok otherwise. It is the string-specific variant of NonZero.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL