Table of Contents

Bodu.Functional Namespace

Package
Bodu.Core 1.0.1

Bodu.Functional

Purpose

Bodu.Functional holds the functional-style building blocks of Bodu.Core: the Memoizer caching factory and the railway-oriented outcome primitives - Option<T> (a value that may be absent), Result / Result<T> with ResultError (success-or-described-failure), and Either<TLeft, TRight> (a symmetric disjoint union). The outcome types are readonly structs that compose through Map / Bind / Match chains, with Task-based async companions.

Three contracts define the family: present values are never null (the strict factories throw; the lenient lifts map null to absence), each type documents its default (Option defaults to None, the Result pair to a failure with an empty error, Either to an explicit uninitialized state whose side-requiring operations throw), and only Result<T> is railway-biased - Either deliberately exposes MapLeft / MapRight rather than an unqualified Map.

Static documentation

  • Introduction - where the functional types sit in the wider Bodu.Core surface.
  • Options, results, and eithers - the railway patterns, the null and default contracts, type bridges, and async composition.
  • Memoization - wrapping a pure function, the comparer overload, multi-argument keys, and the thread-safety and unbounded-cache caveats.

Key types

  • Option<T> - Some / None with Map, Bind, Filter, Match, the GetValueOrDefault family, and ToResult; the non-generic Option companion adds inference-friendly factories and FromNullable.
  • Result<T> / Result - the success/failure rail: Map, Bind, MapError, Tap / TapError, Match, GetValueOrThrow, ToOption; factories live on the non-generic Result.
  • ResultError - the failure descriptor: optional Code, never-null Message, optional captured Exception (attached as InnerException by GetValueOrThrow, never rethrown directly).
  • Either<TLeft, TRight> - Left / Right with TryGetLeft / TryGetRight, Match, MapLeft / MapRight, and Swap.
  • OptionAsyncExtensions / ResultAsyncExtensions - Task-based MapAsync / BindAsync / MatchAsync (plus TapAsync / TapErrorAsync) over both task and sync sources.
  • Memoizer - wraps a pure function with a thread-safe unbounded cache (single- and two-argument overloads, optional key comparer).

Example

using Bodu.Functional;

Result<Order> ParseOrder(string json) =>
    TryParse(json, out var order)
        ? Result.Success(order)
        : Result.Failure<Order>(ResultError.FromMessage("The payload is not a valid order.", code: "ORD001"));

var confirmation = ParseOrder(payload)
    .Bind(Validate)
    .Map(o => o.ConfirmationNumber)
    .TapError(e => log.Warn(e.Message))
    .GetValueOrDefault("(none)");

Notes

  • Absence is typed, never null. Option<T>.Some, Result.Success<T>, and the Either factories reject null with ArgumentNullException; the implicit T → Option<T> conversion and Option.FromNullable are the lenient lifts that map null to None.
  • Totality by documented default. default(Option<T>) is None and default(Result<T>) is a failure carrying an empty ResultError, so fields and array elements are safe uninitialized. default(Either<,>) is the deliberate exception: with no privileged side, it throws from side-requiring operations (the ImmutableArray<T>.IsDefault precedent).
  • Async combinators take no CancellationToken. They perform no I/O of their own; cancellation belongs inside the caller's delegates. Guards throw synchronously and every await uses ConfigureAwait(false).
  • Memoizer caveats. Only successful results are cached, the cache is unbounded, and argument types are notnull - see the guide for details; reach for EvictingDictionary<TKey, TValue> when eviction is needed.

Classes

EitherAsyncExtensions

Provides Task-based asynchronous companions to the Either<TLeft, TRight> combinators.

Memoizer

Provides factory methods that wrap a function with a thread-safe cache, so each distinct argument is computed at most once and subsequent calls return the stored result.

Option

Provides factory methods for creating Option<T> values with type inference at the call site.

OptionAsyncExtensions

Provides Task-based asynchronous companions to the Option<T> railway combinators.

ResultAsyncExtensions

Provides Task-based asynchronous companions to the Result<T> and non-generic Result railway combinators.

Structs

Either<TLeft, TRight>

Represents a disjoint union of two possibilities: either Left(value) carrying a non-null value of type TLeft, or Right(value) carrying a non-null value of type TRight.

Option<T>

Represents an optional value: either Some(value) carrying a non-null value of type T, or None carrying nothing.

Result

Represents the outcome of an operation that produces no value: either Success, or Failure(error) carrying a ResultError.

ResultError

Represents the error carried by a failed Result or Result<T>: a human-readable message, an optional machine-readable code, and an optional originating exception.

Result<T>

Represents the outcome of an operation that produces a value: either Success(value) carrying a non-null value of type T, or Failure(error) carrying a ResultError.