Bodu.Functional Namespace
- Package
-
Bodu.Core 1.0.1
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.Coresurface. - Options, results, and eithers - the railway patterns, the null and
defaultcontracts, 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/NonewithMap,Bind,Filter,Match, theGetValueOrDefaultfamily, andToResult; the non-generic Option companion adds inference-friendly factories andFromNullable. - Result<T> / Result - the success/failure rail:
Map,Bind,MapError,Tap/TapError,Match,GetValueOrThrow,ToOption; factories live on the non-genericResult. - ResultError - the failure descriptor: optional
Code, never-nullMessage, optional capturedException(attached asInnerExceptionbyGetValueOrThrow, never rethrown directly). - Either<TLeft, TRight> -
Left/RightwithTryGetLeft/TryGetRight,Match,MapLeft/MapRight, andSwap. - OptionAsyncExtensions / ResultAsyncExtensions - Task-based
MapAsync/BindAsync/MatchAsync(plusTapAsync/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 theEitherfactories rejectnullwithArgumentNullException; the implicitT→Option<T>conversion andOption.FromNullableare the lenient lifts that mapnulltoNone. - Totality by documented
default.default(Option<T>)isNoneanddefault(Result<T>)is a failure carrying an emptyResultError, so fields and array elements are safe uninitialized.default(Either<,>)is the deliberate exception: with no privileged side, it throws from side-requiring operations (theImmutableArray<T>.IsDefaultprecedent). - 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 usesConfigureAwait(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.
- 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 typeTLeft, orRight(value)carrying a non-null value of typeTRight.
- Option<T>
Represents an optional value: either
Some(value)carrying a non-null value of typeT, orNonecarrying nothing.
- Result
Represents the outcome of an operation that produces no value: either
Success, orFailure(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 typeT, orFailure(error)carrying a ResultError.