Skip to content

Instantly share code, notes, and snippets.

@AlexeyRaga
Last active September 6, 2023 08:50
Show Gist options
  • Save AlexeyRaga/a92e1747cfbf27dd0bda4f5aef2df303 to your computer and use it in GitHub Desktop.
Save AlexeyRaga/a92e1747cfbf27dd0bda4f5aef2df303 to your computer and use it in GitHub Desktop.
Maybe in C#
public readonly struct Option<T> : IEquatable<Option<T>>
{
private readonly T? _value;
public bool HasValue { get; }
public T Value
{
get
{
if (!HasValue) throw new InvalidOperationException("Option does not have a value.");
return _value!;
}
}
private Option(T? value, bool hasValue)
{
_value = value;
HasValue = hasValue;
}
public static Option<T> Some(T value) => new(value, true);
public static Option<T> None() => new(default, false);
public override bool Equals(object? obj) => obj is Option<T> other && Equals(other);
public override int GetHashCode() => HashCode.Combine(_value, HasValue);
public override string ToString() => HasValue ? $"Some({_value?.ToString()})" : "None";
public bool Equals(Option<T> other) =>
HasValue == other.HasValue && EqualityComparer<T?>.Default.Equals(_value, other._value);
public static bool operator ==(Option<T> left, Option<T> right) => left.Equals(right);
public static bool operator !=(Option<T> left, Option<T> right) => !(left == right);
}
public static class Option
{
public delegate bool OutFunc<in TSource, TResult>(TSource source, out TResult result);
public delegate bool OutFunc<in TSource, in TParam, TResult>(TSource source, TParam param, out TResult result);
public static Option<T> Some<T>(T value) => Option<T>.Some(value);
public static Option<T> None<T>() => Option<T>.None();
public static T ValueOrDefault<T>(this Option<T> source, T defaultValue) =>
source.HasValue ? source.Value : defaultValue;
public static T ValueOrDefault<T>(this Option<T> source, Func<T> defaultValue) =>
source.HasValue ? source.Value : defaultValue();
public static Option<TResult>
TryGetValue<TSource, TResult>(TSource source, OutFunc<TSource, TResult> tryGetValue) =>
tryGetValue(source, out var result) ? Some(result) : None<TResult>();
public static Option<TResult> TryGetValue<TSource, TParam, TResult>(TSource source, TParam param,
OutFunc<TSource, TParam, TResult> tryGetValue) =>
tryGetValue(source, param, out var result) ? Some(result) : None<TResult>();
public static Option<T> Some<T>(T? value) where T : struct
{
if (!value.HasValue) throw new ArgumentNullException(nameof(value));
return Option<T>.Some(value.Value);
}
public static Option<T> FromValue<T>(T? value) where T : class => value == null ? None<T>() : Some(value);
public static Option<T> FromValue<T>(T? value) where T : struct => value.HasValue ? Some(value.Value) : None<T>();
}
public static class OptionExtensions
{
public static T? ToNullable<T>(this Option<T> value) where T : class => value.HasValue ? value.Value : null;
public static T? ToNullableStruct<T>(this Option<T> value) where T : struct => value.HasValue ? value.Value : null;
public static Option<TResult> TryGetValue<TSource, TResult>(this TSource source,
Option.OutFunc<TSource, TResult> tryGetValue) =>
Option.TryGetValue(source, tryGetValue);
public static Option<TResult> TryGetValue<TSource, TParam, TResult>(this TSource source, TParam param,
Option.OutFunc<TSource, TParam, TResult> tryGetValue) =>
Option.TryGetValue(source, param, tryGetValue);
public static Option<TResult> Select<TSource, TResult>(
this Option<TSource> source,
Func<TSource, TResult> transform) =>
source switch
{
{ HasValue: true } => Option.Some(transform(source.Value)),
_ => Option.None<TResult>()
};
public static Option<TResult> SelectMany<TSource, TResult>(
this Option<TSource> source,
Func<TSource, Option<TResult>> transform) =>
source switch
{
{ HasValue: true } => transform(source.Value),
_ => Option.None<TResult>()
};
public static Option<TResult> SelectMany<TSource, TCollection, TResult>(
this Option<TSource> source,
Func<TSource, Option<TCollection>> binder,
Func<TSource, TCollection, TResult> selector) =>
source.SelectMany(src => binder(src).Select(x => selector(src, x)));
public static Option<T> Where<T>(this Option<T> source, Func<T, bool> predicate) =>
source switch
{
{ HasValue: true } when predicate(source.Value) => source,
_ => Option.None<T>()
};
public static IEnumerable<T> Collect<T>(this IEnumerable<Option<T>> values) =>
from value in values where value.HasValue select value.Value;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment