option

package
v0.42.0 Latest Latest
Warning

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

Go to latest
Published: Mar 17, 2026 License: MIT Imports: 8 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 LiftErr added in v0.42.0

func LiftErr[A, B any](fn func(A) (B, error)) func(A) Option[B]

LiftErr transforms a function returning (B, error) into one returning Option[B]. The returned function returns ok when err is nil, not-ok otherwise. The original error is discarded; use the unwrapped function directly when error details matter. Panics if fn is nil.

Use LiftErr to adapt any error-returning function for use with FlatMap:

parseDuration := option.LiftErr(time.ParseDuration)
timeout := option.FlatMap(option.Env("TIMEOUT"), parseDuration).Or(5 * time.Second)

For multi-argument stdlib functions, wrap in a closure:

parseInt64 := option.LiftErr(func(s string) (int64, error) {
    return strconv.ParseInt(s, 10, 64)
})

For common cases, prefer the named helpers Atoi, ParseFloat64, ParseBool.

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]

func ParseBool added in v0.42.0

func ParseBool(s string) Bool

ParseBool parses s as a boolean using strconv.ParseBool. Accepts: 1, t, T, TRUE, true, True, 0, f, F, FALSE, false, False. Returns ok if parsing succeeds, not-ok otherwise. Valid "false" input returns Ok(false); invalid input returns not-ok.

On parse failure, returns not-ok; when combined with Option.Or, malformed and missing input are treated the same.

type Byte

type Byte = Option[byte]

type Error

type Error = Option[error]

type Int

type Int = Option[int]

func Atoi added in v0.42.0

func Atoi(s string) Int

Atoi parses s as a base-10 integer. Returns ok if strconv.Atoi succeeds, not-ok otherwise.

Parse failure returns not-ok, not an error. When combined with Option.Or, malformed input is treated the same as missing input:

option.FlatMap(option.Env("PORT"), option.Atoi).Or(8080)

This silently defaults on both missing and non-integer values like "abc". Combined with Env, unset, empty, and malformed env vars all collapse to the same default. Use strconv.Atoi directly when parse errors need distinct handling.

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 ParseFloat64 added in v0.42.0

func ParseFloat64(s string) Option[float64]

ParseFloat64 parses s as a finite 64-bit float using strconv.ParseFloat. Returns not-ok on syntax errors, range errors, and non-finite results (NaN, Inf). Only finite values return ok.

To accept non-finite values, use LiftErr with a closure:

parseAnyFloat := option.LiftErr(func(s string) (float64, error) {
    return strconv.ParseFloat(s, 64)
})

On parse failure, returns not-ok; when combined with Option.Or, malformed and missing input are treated the same.

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