Table of Contents

Either<TLeft, TRight>

Either<TLeft, TRight> represents a value that is one of two possible types. Unlike Result, both sides are equally valid — there's no success/failure bias. Use it for branching logic where both paths represent legitimate outcomes.

Creating Eithers

// Explicit construction
var left  = Either.Left<string, int>("hello");
var right = Either.Right<string, int>(42);

// Implicit conversion
Either<string, int> fromLeft  = "hello";
Either<string, int> fromRight = 42;

Transforming Values

MapLeft / MapRight

Transform one side independently:

var result = Either.Left<string, int>("hello")
    .MapLeft(s => s.Length);  // Left(5)

var result = Either.Right<string, int>(42)
    .MapRight(x => x * 2);   // Right(84)

Map (both sides)

Transform both sides in one call:

var result = either.Map(
    leftMapper:  s => s.Length,
    rightMapper: x => x * 2);

Bind

Chain operations on the right side:

var result = Either.Right<string, int>(42)
    .Bind(x => x > 0
        ? Either.Right<string, int>(x * 2)
        : Either.Left<string, int>("must be positive"));

Pattern Matching

var message = either.Match(
    left:  s => $"Text: {s}",
    right: n => $"Number: {n}");

Side Effects

either
    .IfLeft(s => Console.WriteLine($"Left: {s}"))
    .IfRight(n => Console.WriteLine($"Right: {n}"));

Swap

Exchange left and right:

Either<int, string> swapped = Either.Left<string, int>("hello").Swap();
// Right("hello")

Extension Methods

using DarkPeak.Functional.Extensions;

// Extract with defaults
var leftVal  = either.GetLeftOrDefault("fallback");
var rightVal = either.GetRightOrDefault(0);

// Merge when both sides are the same type
Either<string, string> e = Either.Left<string, string>("hello");
string merged = e.Merge(); // "hello"

// Flatten nested Eithers
Either<Either<string, int>, int> nested = /* ... */;
Either<string, int> flat = nested.Flatten();

// Partition a collection
var (lefts, rights) = items.Partition();

LINQ Support

LINQ query syntax operates on the right side:

var result =
    from x in Either.Right<string, int>(10)
    from y in Either.Right<string, int>(20)
    select x + y; // Right(30)

Async Operations

var result = await either
    .MapLeftAsync(async s => await TranslateAsync(s))
    .MapRightAsync(async n => await EnrichAsync(n))
    .MatchAsync(
        left:  async s => await FormatLeftAsync(s),
        right: async n => await FormatRightAsync(n));