Res Structure

Valueless result type which can be either of the two variants: Ok or Err(error-message).

Definition

Namespace: Orx.Fun.Result
Assembly: Orx.Fun.Result (in Orx.Fun.Result.dll) Version: 1.3.0+344c8bdd6f720ccfb2d8db7c61b76cf02be18f5f
C#
public readonly struct Res
Inheritance
Object    ValueType    Res

Constructors

Res Result type which can either be Ok or Err. Parameterless ctor returns Ok; better use Ok or Err(String) to construct results by adding `using static OptRes.Ext`.

Properties

IsErr True if the result is Err; false otherwise.
IsOk True if the result is Ok; false otherwise.

Methods

And Combines two results: this and other as follows:
  • returns Ok if both are Ok;
  • returns the error if one of the results is an Err;
  • returns the combined error if both results are Err.
AndAllT1, T2(FuncResT1, FuncResT2) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
AndAllT1, T2(ResT1, ResT2) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
AndAllT1, T2, T3(FuncResT1, FuncResT2, FuncResT3) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
AndAllT1, T2, T3(ResT1, ResT2, ResT3) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
AndAllT1, T2, T3, T4(FuncResT1, FuncResT2, FuncResT3, FuncResT4) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
AndAllT1, T2, T3, T4(ResT1, ResT2, ResT3, ResT4) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
AndAllT1, T2, T3, T4, T5(FuncResT1, FuncResT2, FuncResT3, FuncResT4, FuncResT5) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
AndAllT1, T2, T3, T4, T5(ResT1, ResT2, ResT3, ResT4, ResT5) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
AndAllT1, T2, T3, T4, T5, T6(FuncResT1, FuncResT2, FuncResT3, FuncResT4, FuncResT5, FuncResT6) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
AndAllT1, T2, T3, T4, T5, T6(ResT1, ResT2, ResT3, ResT4, ResT5, ResT6) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
AndAllT1, T2, T3, T4, T5, T6, T7(FuncResT1, FuncResT2, FuncResT3, FuncResT4, FuncResT5, FuncResT6, FuncResT7) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
AndAllT1, T2, T3, T4, T5, T6, T7(ResT1, ResT2, ResT3, ResT4, ResT5, ResT6, ResT7) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
AndAllT1, T2, T3, T4, T5, T6, T7, T8(FuncResT1, FuncResT2, FuncResT3, FuncResT4, FuncResT5, FuncResT6, FuncResT7, FuncResT8) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
AndAllT1, T2, T3, T4, T5, T6, T7, T8(ResT1, ResT2, ResT3, ResT4, ResT5, ResT6, ResT7, ResT8) Returns the tuple combining unwrapped values of the results if all of them are of Ok variant; returns first Err otherwise.
Do Runs action() only if IsOk; and returns itself back.
C#
User user = CreateUser(/*inputs*/);
Res result = TryPutUserToDb(user).Do(Log.Success("user created"));
// result will be:
// - Ok if TryPutUserToDb succeeds and returns Ok; in this case the success message will be logged; or
// - Err if TryPutUserToDb returns Err; and the success message log will not be called.
DoIfErr(Action) Runs action() only if IsErr; and returns itself back. This is the counterpart of the Do(Action) method.
C#
Res result = RefreshIndices(/*inputs*/).DoIfErr(() => Alert("database connection failed"));
// result will be:
// - Ok if refreshing db indices succeeded;
// - Err if it failed, in which case the Alert call will be made.
DoIfErr(ActionString) Runs action(error-message) only if IsErr; and returns itself back. This is the counterpart of the Do(Action) method.
C#
Res result = RefreshIndices(/*inputs*/).DoIfErr(err =>  Alert($"database connection failed: {err}"));
// result will be:
// - Ok if refreshing db indices succeeded;
// - Err if it failed, in which case the Alert call will be made.
Equals
(Inherited from ValueType)
ErrorMessage Returns Some(error-message) if IsErr; None<string>() if IsOk.
C#
var result = Err("failed to connect");
Assert(result.ErrorMessage() == Some("failed to connect"));
FlatMap(FuncRes) Returns the error when IsErr; map() when IsOk, flattenning the result. This is a shorthand for sequential Map and Flatten calls.
C#
// assume we have two methods that can fail; hence returns a Res:
static Res TryRunRiskyOperation() { .. }
static Res TryLogCompletion() { .. }

// we want to call both operations; but the second one only if the first one succeeds.
Res result = TryRunRiskyOperation().FlatMap(TryLogCompletion);
// alternatively:
Res result = TryRunRiskyOperation().FlatMap(() => TryLogCompletion());

// this is equivalent to:
Res result = TryRunRiskyOperation().Map(() => TryLogCompletion()/*Res<Res>*/).Flatten()/*Res*/;
FlatMapTOut(FuncResTOut) Returns the error when IsErr; map() when IsOk, flattenning the result. This is a shorthand for sequential Map and Flatten calls.
C#
// assume we have two methods that can fail; hence returns a Res:
static Res TryRunRiskyOperation() { .. }
static Res<int> TryGetCount() { .. }

// we want to call both operations; but the second one only if the first one succeeds.
Res result = TryRunRiskyOperation().FlatMap(TryGetCount);
// alternatively:
Res result = TryRunRiskyOperation().FlatMap(() => TryGetCount());

// this is equivalent to:
Res result = TryRunRiskyOperation().Map(() => TryGetCount()/*Res<Res<int>>*/).Flatten()/*Res<int>*/;
FlatMapAsync(FuncTaskRes) (async version) Returns the error when IsErr; map() when IsOk, flattenning the result. This is a shorthand for sequential Map and Flatten calls.
C#
// assume we have two methods that can fail; hence returns a Res:
static Res TryRunRiskyOperation() { .. }
static Res TryLogCompletion() { .. }

// we want to call both operations; but the second one only if the first one succeeds.
Res result = TryRunRiskyOperation().FlatMap(TryLogCompletion);
// alternatively:
Res result = TryRunRiskyOperation().FlatMap(() => TryLogCompletion());

// this is equivalent to:
Res result = TryRunRiskyOperation().Map(() => TryLogCompletion()/*Res<Res>*/).Flatten()/*Res*/;
FlatMapAsyncTOut(FuncTaskResTOut) (async version) Returns the error when IsErr; map() when IsOk, flattenning the result. This is a shorthand for sequential Map and Flatten calls.
C#
// assume we have two methods that can fail; hence returns a Res:
static Res TryRunRiskyOperation() { .. }
static Res<int> TryGetCount() { .. }

// we want to call both operations; but the second one only if the first one succeeds.
Res result = TryRunRiskyOperation().FlatMap(TryGetCount);
// alternatively:
Res result = TryRunRiskyOperation().FlatMap(() => TryGetCount());

// this is equivalent to:
Res result = TryRunRiskyOperation().Map(() => TryGetCount()/*Res<Res<int>>*/).Flatten()/*Res<int>*/;
GetHashCode
(Inherited from ValueType)
GetType
(Inherited from Object)
MapTOut Returns the error when IsErr; Ok(map()) when IsOk.
C#
Res ValidateInputs(Inputs inputs) { /*checks*/ }
Output CalcOutput(Inputs inputs) { /*maps inputs to output*/ }

Inputs inputs = GetInputs();
Res<Output> output = ValidateInputs(inputs).Map(() => CalcOutput(inputs));
// output will be:
// - Err if ValidateInputs returns Err omitting the call to CalcOutput;
// - Ok(CalcOutput(inputs)) if ValidateInputs returns Ok.
MapAsyncTOut (async version) Returns the error when IsErr; Ok(map()) when IsOk.
C#
Res ValidateInputs(Inputs inputs) { /*checks*/ }
Output CalcOutput(Inputs inputs) { /*maps inputs to output*/ }

Inputs inputs = GetInputs();
Res<Output> output = ValidateInputs(inputs).Map(() => CalcOutput(inputs));
// output will be:
// - Err if ValidateInputs returns Err omitting the call to CalcOutput;
// - Ok(CalcOutput(inputs)) if ValidateInputs returns Ok.
MatchTOut(FuncTOut, FuncString, TOut) Maps into whenOk() lazily whenever IsOk; and into whenErr(errorMessage) otherwise. Similar to MatchTOut(TOut, FuncString, TOut) except that whenOk is lazy and evaluated only when IsOk.
MatchTOut(TOut, FuncString, TOut) Maps into whenOk whenever IsOk; and into whenErr(errorMessage) otherwise.
C#
Res<User> user = TryGetUser(..);
string greetingMessage = user.Match("Welcome", err => $"Error getting the user: {err}");
MatchAsyncTOut (async version) Maps into whenOk() lazily whenever IsOk; and into whenErr(errorMessage) otherwise. Similar to MatchTOut(TOut, FuncString, TOut) except that whenOk is lazy and evaluated only when IsOk.
MatchDo Executes whenOk() whenever IsOk; and whenErr(errorMessage) otherwise.
C#
Res<User> user = TryGetUser(..);
user.MatchDo
(
    whenOk: () => Log.Info("New user login"),
    whenErr: err => Log.Error($"Failed login. {err}")
);
OkIf(Boolean, String) Returns back the Err if this is Err. Otherwise, returns Ok if okCondition holds; Err if it does not hold. Especially useful in fluent input validation.
C#
static Res<User> Login(string username, string passwordHash)
{
    return OkIf(!string.IsNullOrEmpty(username))    // validate username
        .OkIf(!string.IsNullOrEmpty(passwordHash))  // validate password-hash
        .OkIf(userRepo.ContainsKey(username))       // further validate user
        .Map(() => GetUser(username, password));    // finally map into actual result;
                                                    // any Err in validation steps will directly be mapped to Err, avoiding GetUser call.
}
OkIf(FuncBoolean, String)

Lazy counterpart of OkIf(Boolean, String) where condition is evaluated only if this is Ok.

Returns back the Err if this is Err. Otherwise, returns Ok if lazyOkCondition holds; Err if it does not hold. Especially useful in fluent input validation.
C#
static Res<User> Login(string username, string passwordHash)
{
    return OkIf(!string.IsNullOrEmpty(username))    // validate username
        .OkIf(!string.IsNullOrEmpty(passwordHash))  // validate password-hash
        .OkIf(() => userRepo.ContainsKey(username)) // further validate user; assume this is an expensive call, so we prefer the lazy variant
        .Map(() => GetUser(username, password));    // finally map into actual result;
                                                    // any Err in validation steps will directly be mapped to Err, avoiding GetUser call.
}
Or(FuncRes) (lazy version) Combines two results: this and other as follows:
  • returns this if this is Ok;
  • returns other otherwise.
C#
var or = Ok().Or(Ok());
Assert.True(or.IsOk);

or = Ok().Or(Err("error-message"));
Assert.True(or.IsOk);

or = Err("error-message").Or(Ok());
Assert.True(or.IsOk);

or = Err("error-message").Or(Err("second-error-message"));
Assert.True(or.IsErr);
Assert.Equal(Some("second-error-message"), or.ErrorMessage());
Or(Res) Combines two results: this and other as follows:
  • returns this if this is Ok;
  • returns other otherwise.
C#
var or = Ok().Or(Ok());
Assert.True(or.IsOk);

or = Ok().Or(Err("error-message"));
Assert.True(or.IsOk);

or = Err("error-message").Or(Ok());
Assert.True(or.IsOk);

or = Err("error-message").Or(Err("second-error-message"));
Assert.True(or.IsErr);
Assert.Equal(Some("second-error-message"), or.ErrorMessage());
Pure Simply returns Ok function: () => Ok(). Useful for composing functions of Res type.
ThrowIfErr Returns the result back when IsOk; throws NullReferenceException when IsErr.
C#
static Res MakeApiCall() {
    // method that makes an api call.
    // might fail; hence, returns a Res rather than void.
}
var result = MakeApiCall().ThrowIfErr();
// result will be:
// - Ok() if MakeApiCall succeeds and returns Ok;
// - the application will throw a NullReferenceException otherwise.
ThrowIfErrE(FuncString, E) Returns the result back when IsOk; throws an exception of E when IsErr.
C#
static Res MakeApiCall() {
    // method that makes an api call.
    // might fail; hence, returns a Res rather than void.
}
var result = MakeApiCall().ThrowIfErr<HttpRequestException>(err => new(err));
// result will be:
// - Ok() if MakeApiCall succeeds and returns Ok;
// - the application will throw HttpRequestException created by the provided delegate otherwise.
ToErrOfTOut Converts the result to Err<TOut> regardless of state of this result:
  • The error message will be carried on when this is of Err variant,
  • A generic error message will be created otherwise.
ToString String representation.
(Overrides ValueTypeToString)
Try When IsOk executes action() in a try-catch block: returns back itself if the process succeeds; Err if it throws. Does not do anything and returns back itself when IsErr.
C#
static Res TryLogin() { .. }
static void ClearSessionHistory() { /*risky function, might throw!*/ }

var result = TryLogin().Try(ClearSessionHistory);
// the result will be:
// - Err if TryLogin returns Err, in which case ClearSessionHistory is never called;
// - Ok if TryLogin returns Ok; and ClearSessionHistory call succeeds without an exception;
// - Err if TryLogin returns Ok, but ClearSessionHistory throws an exception.
TryAsync (async version) When IsOk executes action() in a try-catch block: returns back itself if the process succeeds; Err if it throws. Does not do anything and returns back itself when IsErr.
C#
static Res TryLogin() { .. }
static void ClearSessionHistory() { /*risky function, might throw!*/ }

var result = TryLogin().Try(ClearSessionHistory);
// the result will be:
// - Err if TryLogin returns Err, in which case ClearSessionHistory is never called;
// - Ok if TryLogin returns Ok; and ClearSessionHistory call succeeds without an exception;
// - Err if TryLogin returns Ok, but ClearSessionHistory throws an exception.
TryFlatMapTOut Returns the error when IsErr. Otherwise, tries to return map(val) in a try-catch block and returns the Err if it throws.
C#
static Res<User> TryGetUser() { .. }
static Res<long> PutUserToDbGetId(User user) {
    // method that writes the user to a database table and returns back the auto-generated id/primary-key
    // might throw in cases of connection errors!
}

Res<long> id = TryGetUser().TryFlatMap(PutUserToDbGetId);
// equivalently:
Res<long> id = TryGetUser().TryFlatMap(user => PutUserToDbGetId(user));
// Res<long> id will be:
// - Err(called on Err) when TryGetUser returns Err,
// - Err(relevant error message) when TryGetUser returns Ok(user) but PutUserToDbGetId returns an Err,
// - Err(relevant error message) when TryGetUser returns Ok(user) but the database transaction throws an exception,
// - Ok(id) when TryGetUser returns Ok(user), the database transaction succeeds and returns the auto-generated id.
TryFlatMapAsyncTOut (async version) Returns the error when IsErr. Otherwise, tries to return map(val) in a try-catch block and returns the Err if it throws.
C#
static Res<User> TryGetUser() { .. }
static Res<long> PutUserToDbGetId(User user) {
    // method that writes the user to a database table and returns back the auto-generated id/primary-key
    // might throw in cases of connection errors!
}

Res<long> id = TryGetUser().TryFlatMap(PutUserToDbGetId);
// equivalently:
Res<long> id = TryGetUser().TryFlatMap(user => PutUserToDbGetId(user));
// Res<long> id will be:
// - Err(called on Err) when TryGetUser returns Err,
// - Err(relevant error message) when TryGetUser returns Ok(user) but PutUserToDbGetId returns an Err,
// - Err(relevant error message) when TryGetUser returns Ok(user) but the database transaction throws an exception,
// - Ok(id) when TryGetUser returns Ok(user), the database transaction succeeds and returns the auto-generated id.
TryMapTOut Returns the error when IsErr. Otherwise, tries to map into Ok(map()) in a try-catch block and returns the Err if it throws.
C#
static Res ValidateUser(User user) { /*returns Ok if valid; Err o/w*/ }
static Res<Secret> TryGetSecrets(User user) { /*returns Ok(secrets) if succeds; Err if fails to get secrets*/ }

User user = GetUser(..);
var secrets = ValidateUser(user).TryMap(() => TryGetSecrets(user));
// TryGetSecrets will be called only if ValidateUser call returns Ok;
// secrets will be Ok of the grabbed secrets if both ValidateUser and TryGetSecrets return Ok.
TryMapAsyncTOut (async version) Returns the error when IsErr. Otherwise, tries to map into Ok(map()) in a try-catch block and returns the Err if it throws.
C#
static Res ValidateUser(User user) { /*returns Ok if valid; Err o/w*/ }
static Res<Secret> TryGetSecrets(User user) { /*returns Ok(secrets) if succeds; Err if fails to get secrets*/ }

User user = GetUser(..);
var secrets = ValidateUser(user).TryMap(() => TryGetSecrets(user));
// TryGetSecrets will be called only if ValidateUser call returns Ok;
// secrets will be Ok of the grabbed secrets if both ValidateUser and TryGetSecrets return Ok.

Operators

BitwiseOr(Res, FuncRes)

Limited ahd experimental for now; waiting for generics in operator overloading to be actually useful.

Returns the error when IsErr; map() when IsOk, flattenning the result. This is a shorthand for sequential Map and Flatten calls.
C#
// assume we have two methods that can fail; hence returns a Res:
static Res TryRunRiskyOperation() { .. }
static Res TryLogCompletion() { .. }

// we want to call both operations; but the second one only if the first one succeeds.
Res result = TryRunRiskyOperation().FlatMap(TryLogCompletion);
// alternatively:
Res result = TryRunRiskyOperation().FlatMap(() => TryLogCompletion());

// this is equivalent to:
Res result = TryRunRiskyOperation().Map(() => TryLogCompletion()/*Res<Res>*/).Flatten()/*Res*/;

See Also