Result - Perustaja/Polyglot GitHub Wiki
Represents either an Ok
with underlying value T
or Err
with underlying value E
. Like with Option
, all
behavior should act as close to possible as it does in Rust's implementation.
var ok = Result<int, string>.Ok(5);
var err = Result<int, string>.Err("Error!");
Two functions are provided to see check if it is Ok
or Err
.
var ok = Result<string, int>.Ok("Hi!");
Console.WriteLine(o.IsOk()); // Prints true
Console.WriteLine(o.IsErr()); // Prints false
Returns the underlying value if current is Ok
, else throws an exception.
var okay = Result<int, string>.Ok(10);
int value = okay.Unwrap(); // Returns 10
var notOkay = Result<int, string>.Err("Oops!");
value = notOkay.Unwrap(); // Throws an exception!
Returns the underlying value if current is Err
, else throws an exception.
var okay = Result<int, string>.Ok(10);
string value = okay.UnwrapErr(); // Throws an exception!
var notOkay = Result<int, string>.Err("Oops!");
value = notOkay.UnwrapErr(); // Returns "Oops!"
Map()
is a function for mapping a Result<T, E>
to a Result<U, E>
by invoking a passed function. If the current is Ok
, the function is invoked
with the underlying value, returning a new Ok
of a different type. If it is Err
, the result is still Err
.
var res = Result<int, string>.Ok(10).Map(n => n.ToString()); // Returns Ok("10")
var none = Result<int, string>.Err("Oops!").Map(n => n.ToString()); // Returns Err("Oops!")
Provides a fallback value to return in case the current is Err
, else returns the result of the function when invoked on the underlying Ok
.
var res = Result<int, string>.Ok(10).MapOr("Default", n => n.ToString()); // Returns Ok("10")
var none = Result<int, string>.Err("Oops!").MapOr("Default", n => n.ToString()); // Returns Ok("Default")
Provides a fallback function to lazily evaluate in a closure if the current is Err
, else returns the result of the function when invoked on the underlying Ok
.
var res = Result<int, string>.Ok(10).MapOrElse(() => "Default", n => n.ToString()); // Returns Ok("10")
var none = Result<int, string>.Err("Oops!").MapOrElse(() => "Default", n => n.ToString()); // Returns Ok("Default")
Map()
is a function for mapping a Result<T, E>
to a Result<T, F>
by invoking a passed function. If the current is Err
, the function is invoked
with the underlying value, returning a new Err
of a different type. If it is Ok
, the result is still Ok
.
var res = Result<string, int>.Ok("Hi!").MapErr(n => n.ToString()); // Returns Ok("Hi!")
var none = Result<string, int>.Err(10).MapErr(n => n.ToString()); // Returns Err("10")
AndThen()
allows chaining. Each function in the chain returns a Result
, calling the passed function on its underlying value if Ok
, or returning Err
if there isn't one. If any of the calls in the chain return Err
, the end result is Err
.
// Assume the following function exists
private Result<int, string> SquareIfOk(Result<int, string> res)
=> res.IsOk()
? res.Map(n => n * 2)
: res;
public void SomeOtherScope()
{
var okay = Result<int, string>.Ok(10);
okay.AndThen(SquareIfOk); // Returns Ok(100)
var notOkay = Result<int, string>.Err("Oops!");
okay.AndThen(SquareIfOk); // Returns Err("Oops!")
}
Returns the current Result
if Ok
, else returns the argument. Note that this does not guarantee the other is Ok
.
var okay = Result<int, string>.Ok(10).Or(Result<int, string>.Ok(20));
// okay: Ok(10)
var notOkay = Result<int, string>.Err("Oops!").Or(Result<int, string>.Ok(20));
// notOkay : Ok(20)
This can be used for I/O operations or when a side effect is desired. This is made to mimic
the match
block in Rust, but obviously has its downsides as you cannot handle many different values
like in Rust.
var res = Result<string, int>.Ok("Ok!");
o.Match(
s => Console.WriteLine(s),
e => someFile.WriteLine(e)
);
// Prints "Ok!" to the console
var res = Result<string, int>.Err(100);
o.Match(
s => Console.WriteLine(s),
e => someFile.WriteLine(e)
);
// Prints 100 to some file
Results
are safe to use in hashed collections. It is also safe to use the ==
operator on them.