I was considering introducing the OneOf library into our codebase, but if this is < a year or so away it might not be worth the effort.
I was considering introducing the OneOf library into our codebase, but if this is < a year or so away it might not be worth the effort.
Really though, you don't need a library to do sum-types in C#:
It's best to just use records for now:
public abstract record Maybe<A>
{
private Maybe() { }
public sealed record Just(A Value) : Maybe<A>;
public sealed record Nothing : Maybe<A>;
}
The private constructor and sealed case-types stops anybody else deriving from `Maybe<A>`, so the type is effectively closed and finite.You can then construct like so:
var mx = new Maybe<int>.Just(123);
var my = new Maybe<int>.Nothing();
Then you can use the pattern-matching: var r = mx switch
{
Maybe<int>.Just (var x) => x,
Maybe<int>.Nothing => 0
};
Of course, we don't get exhaustiveness checking, that'll have to wait for the proper sum-types (although the compiler does some pretty good work on this right now); but until then this is the most expressive and powerful way of doing sum-types in C#.And, if you want a load of pre-built ones, then my library language-ext will help [1]
public record UhOh<A> : Maybe<A>
{
public UhOh() : base(new Maybe<A>.Nothing())
{
}
}
Maybe<int> m = new UhOh<int>();I implemented my own option types entirely differently via ref structs where the "non-option" becomes either a default of a value type or a null reference (size of a pointer). Then (in theory) the overhead is reduced to a single dereference with everything else being stack-allocated.
I then built the same thing as a non ref (regular) struct version for storing in a field. So I have Options.Quick and Options.Long namespaces with practically the same struct design just the former is a ref struct.
This has served me very well, is very fast. It just doesn't have the exhaustive checking and risks derefing a null reference, but in practice is not a big issue.
if(option.IsT1){ doSomething(option.ValueT1)};
if(option.IsT1){doSomething(option.ValueT2)}; // this would throw an exception, i.e. a bug, but its very readable to catch the bug.NET releases are every November, and I would be very surprised to see this in November 2024. More likely November 2025 at soonest. But check back to that page later.