Struct Maybe<T>

Namespace
REslava.Result.AdvancedPatterns
Assembly
REslava.Result.dll

Represents an optional value that may or may not exist. A functional programming alternative to null references.

public readonly struct Maybe<T> : IEquatable<Maybe<T>>

Type Parameters

T

The type of the optional value

Implements
Inherited Members
Extension Methods

Remarks

Maybe<T> is a type-safe way to handle optional values without using null references. It can be in one of two states: Some(T) when it contains a value, or None when it's empty.

This eliminates the need for null checks and provides a functional approach to handling potentially missing values.

// Instead of:
string? name = GetUser();
if (name != null) {
    Console.WriteLine(name.ToUpper());
}

// Use Maybe: Maybe<string> name = GetUser(); var upperName = name.Map(n => n.ToUpper());

Properties

HasValue

Gets whether this Maybe has a value.

public bool HasValue { get; }

Property Value

bool

true if this Maybe contains a value; otherwise, false.

Examples

Maybe<string> maybe = Maybe<string>.Some("hello");
if (maybe.HasValue) {
    Console.WriteLine("Has value");
}

Remarks

Use this property to check if the Maybe contains a value before accessing it. This is safer than checking for null.

None

Creates a Maybe without a value (None).

public static Maybe<T> None { get; }

Property Value

Maybe<T>

A Maybe representing the absence of a value.

Examples

Maybe<string> empty = Maybe<string>.None;
Maybe<int> noNumber = Maybe<int>.None;

Remarks

This is the singleton instance representing an empty Maybe. Use this when you want to represent the absence of a value.

Value

Gets the value if it exists, throws if not.

public T Value { get; }

Property Value

T

The contained value.

Examples

Maybe<int> maybe = Maybe<int>.Some(42);
int value = maybe.Value; // Returns 42

Maybe<int> empty = Maybe<int>.None;
int value2 = empty.Value; // Throws InvalidOperationException

Remarks

Only access this property when you're certain the Maybe contains a value. Consider using ValueOrDefault(T) or Match<TResult>(Func<T, TResult>, Func<TResult>) for safer access.

Exceptions

InvalidOperationException

Thrown when the Maybe has no value.

Methods

Bind<TResult>(Func<T, Maybe<TResult>>)

Chains operations that return Maybe.

public Maybe<TResult> Bind<TResult>(Func<T, Maybe<TResult>> binder)

Parameters

binder Func<T, Maybe<TResult>>

The function that takes the value and returns a Maybe.

Returns

Maybe<TResult>

The result of the binder function, or None if the original was None.

Type Parameters

TResult

The type of the result Maybe.

Examples

Maybe<int> userId = Maybe<int>.Some(123);
Maybe<string> userName = userId.Bind(id => FindUserById(id));

Maybe<int> invalidId = Maybe<int>.None;
Maybe<string> noUser = invalidId.Bind(id => FindUserById(id)); // None

Remarks

Bind (also known as flatMap or chain) allows you to chain operations that return Maybe. This is useful for sequential operations where each step might fail.

Exceptions

ArgumentNullException

Thrown when binder is null.

Equals(Maybe<T>)

Indicates whether the current object is equal to another object of the same type.

public bool Equals(Maybe<T> other)

Parameters

other Maybe<T>

An object to compare with this object.

Returns

bool

true if the current object is equal to the other parameter; otherwise, false.

Equals(object?)

Indicates whether this instance and a specified object are equal.

public override bool Equals(object? obj)

Parameters

obj object

The object to compare with the current instance.

Returns

bool

true if obj and this instance are the same type and represent the same value; otherwise, false.

Filter(Func<T, bool>)

Keeps the value only if it satisfies the predicate.

public Maybe<T> Filter(Func<T, bool> predicate)

Parameters

predicate Func<T, bool>

The condition to test the value against.

Returns

Maybe<T>

The original Maybe if the predicate is true, otherwise None.

Examples

Maybe<int> number = Maybe<int>.Some(10);
Maybe<int> positive = number.Filter(n => n > 0); // Some(10)
Maybe<int> large = number.Filter(n => n > 100); // None

Maybe<int> empty = Maybe<int>.None;
Maybe<int> stillEmpty = empty.Filter(n => n > 0); // None

Remarks

Filter allows you to conditionally keep or discard the value. If the Maybe is None, the predicate is not evaluated and None is returned.

Exceptions

ArgumentNullException

Thrown when predicate is null.

GetHashCode()

Returns the hash code for this instance.

public override int GetHashCode()

Returns

int

A 32-bit signed integer that is the hash code for this instance.

Map<TResult>(Func<T, TResult>)

Transforms the value if it exists.

public Maybe<TResult> Map<TResult>(Func<T, TResult> mapper)

Parameters

mapper Func<T, TResult>

The function to apply to the value if it exists.

Returns

Maybe<TResult>

A new Maybe containing the transformed value, or None if the original was None.

Type Parameters

TResult

The type of the transformed value.

Examples

Maybe<int> number = Maybe<int>.Some(5);
Maybe<string> text = number.Map(n => $"Number: {n}"); // Some("Number: 5")

Maybe<int> empty = Maybe<int>.None;
Maybe<string> noText = empty.Map(n => $"Number: {n}"); // None

Remarks

Map allows you to transform the contained value without unwrapping the Maybe. If the Maybe is None, the mapper function is not called and None is returned.

Exceptions

ArgumentNullException

Thrown when mapper is null.

Match<TResult>(Func<T, TResult>, Func<TResult>)

Pattern matching - executes the appropriate function.

public TResult Match<TResult>(Func<T, TResult> some, Func<TResult> none)

Parameters

some Func<T, TResult>

The function to execute when the Maybe has a value.

none Func<TResult>

The function to execute when the Maybe has no value.

Returns

TResult

The result of the executed function.

Type Parameters

TResult

The type of the result.

Examples

Maybe<int> number = Maybe<int>.Some(42);
string message = number.Match(
    some: n => $"The number is {n}",
    none: () => "No number available"
); // "The number is 42"

Maybe<int> empty = Maybe<int>.None;
string message2 = empty.Match(
    some: n => $"The number is {n}",
    none: () => "No number available"
); // "No number available"

Remarks

Match provides a way to handle both cases (Some and None) in a type-safe manner. This is similar to pattern matching in functional languages.

Exceptions

ArgumentNullException

Thrown when some or none is null.

Some(T)

Creates a Maybe with a value (Some).

public static Maybe<T> Some(T value)

Parameters

value T

The value to wrap in a Maybe.

Returns

Maybe<T>

A Maybe containing the specified value.

Examples

Maybe<string> name = Maybe<string>.Some("Alice");
Maybe<int> age = Maybe<int>.Some(25);
Maybe<string?> nullable = Maybe<string?>.Some(null);

Remarks

This is the factory method for creating a Maybe that contains a value. The value can be null, in which case it will still be wrapped in a Some.

Tap(Action<T>)

Executes an action if the value exists.

public Maybe<T> Tap(Action<T> action)

Parameters

action Action<T>

The action to execute with the contained value.

Returns

Maybe<T>

The original Maybe for method chaining.

Examples

Maybe<string> name = Maybe<string>.Some("Alice");
var result = name
    .Tap(n => Console.WriteLine($"Processing: {n}"))
    .Map(n => n.ToUpper());
// Output: "Processing: Alice"
// result: Some("ALICE")

Remarks

Tap is useful for side effects like logging without breaking the Maybe chain. The Maybe is returned unchanged, allowing further chaining.

Exceptions

ArgumentNullException

Thrown when action is null.

TapNone(Action)

Executes an action if the value doesn't exist.

public Maybe<T> TapNone(Action action)

Parameters

action Action

The action to execute when the Maybe has no value.

Returns

Maybe<T>

The original Maybe for method chaining.

Examples

Maybe<string> name = Maybe<string>.None;
var result = name
    .TapNone(() => Console.WriteLine("Using default name"))
    .ValueOrDefault("Default");
// Output: "Using default name"
// result: "Default"

Remarks

TapNone is useful for handling the None case with side effects like logging defaults. The Maybe is returned unchanged, allowing further chaining.

Exceptions

ArgumentNullException

Thrown when action is null.

ToString()

Converts to string for debugging.

public override string ToString()

Returns

string

A string representation of the Maybe.

Examples

Maybe<string> name = Maybe<string>.Some("Alice");
Console.WriteLine(name.ToString()); // "Some(Alice)"

Maybe<int> empty = Maybe<int>.None;
Console.WriteLine(empty.ToString()); // "None"

Remarks

Returns "Some(value)" when the Maybe contains a value, or "None" when empty. This is primarily useful for debugging and logging.

ValueOrDefault(T)

Gets the value or returns a default.

public T ValueOrDefault(T defaultValue = default)

Parameters

defaultValue T

The default value to return when no value exists.

Returns

T

The contained value or the specified default.

Examples

Maybe<string> name = Maybe<string>.Some("Alice");
string result1 = name.ValueOrDefault("Default"); // "Alice"

Maybe<string> empty = Maybe<string>.None;
string result2 = empty.ValueOrDefault("Default"); // "Default"

Remarks

This is a safe way to extract the value without throwing exceptions. It's equivalent to the null-coalescing operator (??) for Maybe.

Operators

operator ==(Maybe<T>, Maybe<T>)

public static bool operator ==(Maybe<T> left, Maybe<T> right)

Parameters

left Maybe<T>
right Maybe<T>

Returns

bool

implicit operator Maybe<T>(T)

Implicit conversion from T to Maybe<T>.

public static implicit operator Maybe<T>(T value)

Parameters

value T

The value to convert to Maybe.

Returns

Maybe<T>

A Maybe containing the specified value.

Examples

Maybe<string> name = "Alice"; // Implicit conversion
Maybe<int> number = 42; // Implicit conversion

// These are equivalent to:
Maybe<string> name2 = Maybe<string>.Some("Alice");
Maybe<int> number2 = Maybe<int>.Some(42);

Remarks

This allows automatic conversion from any value to Maybe, making the code more concise. Null values will be wrapped in Some(null), not converted to None.

operator !=(Maybe<T>, Maybe<T>)

public static bool operator !=(Maybe<T> left, Maybe<T> right)

Parameters

left Maybe<T>
right Maybe<T>

Returns

bool