Core Functionality
Learn about the different functionality that is common to both the Option and Result types.
Introduction
While Option<T> and Result<T, E> serve different purposes (absence vs. success/failure), they share a common operational model. If you are fluent with either the Option<T> or Result<T, E> already, you're 90% of the way to mastering the other.
The core APIs defined below work the same across both types, differing only in terms of semantics.
Creation
Both Option and Result types have factory methods that allow you to create an instance of the monad in one of it's two states.
Option<string> some = Option.Some("Hello Bees!");
Option<string> none = Option.None<string>();Result<int, string> ok = Result.Ok<int, string>(1);
Result<int, string> err = Result.Err<int, string>("Something went wrong...");Use Try to safely capture potentially exception-throwing logic inside a monadic wrapper. This is useful if you want to begin a monadic chain from a method you do not have control over.
Option<User> maybeUser = Option.Try(() => GetCurrentUser());If the GetCurrentUser call throws, the exception is caught and logged via your configured exception logger, and you get back a None<User> instance.
Result<User, string> result = Result.Try(
onOk: () => GetCurrentUser(),
onErr: ex => ex.Message
);If the GetCurrentUser call throws, the exception is caught and logged via your configured exception logger, and the onErr delegate you provide is invoked.
Transform
Transformations are the bread and butter of monadic chains. They are used to transform the value inside the monadic wrapper and perform operations on them.
Map
Map is the most common transform. Use Map to apply a transformation to the contained value if it is present or successful.
More Transforms
There are additional transform methods specific to the Option<T> and Result<T, E> types.
State Checks
Use IsOk and IsErr when you need to check the state of the Result<T, E> and don't need to access it's value just quite yet.
Use IsSome and IsNone when you want to check the state of the monad and don't need to access it's value just quite yet.
Consume
You will eventually need to escape from a monadic wrapper in order to access to a concrete value. This is where consume methods come in.
Match
Use Match to consume the monadic wrapper when you are uncertain of the wrapper's current state. It enables you to pattern match on the outcome and apply branching logic.
Unwrap
Use Unwrap to consume the monadic wrapper when you are certain the monadic wrapper holds a value, or if you want to fail loudly if it doesn't.
An UnwrapException will be thrown when the value is absent or failure.
UnwrapOr
An alternative to Unwrap, use UnwrapOr to consume the monadic wrapper when you have a fallback value prepared for the None or Err states.
UnwrapOrElse
An alternative to UnwrapOr, use UnwrapOrElse to consume the monadic wrapper when you have a fallback value that requires some expensive computation.
UnwrapOrDefault
An alternative to Unwrap, use UnwrapOrDefault to consume the monadic wrapper when you are ok with default(T) as the fallback value.
Expect
A sibling to Unwrap, but allows you to provide a meaningful error message when an exception is thrown. Use Expect to consume the monadic wrapper when you expect it to be in a Some or Ok state, and you want to fail loudly if it isn't.
An UnmetExpectationException with your provided message will be thrown when the value is absent or failure.
More Consumes
There are consume methods specific to a Result<T, E>.
Transform and Consume
MapOr
Use MapOr when you want to apply a transformation to the contained value, and you have a fallback value ready to go in case the monadic wrapper is a None or Err. If your fallback value requires expensive computation, reach for MapOrElse.
MapOrElse
Use MapOrElse when you want to apply a transformation to the contained value, consume the monadic wrapper, and you need to perform an expensive calculation to get the fallback value.
Side-Effect
Side effects allow you to conditionally access the value when it is Some or Ok and run some logic against the value without having to handle the other branch.
Inspect
Use Inspect when you want to run some logic against the value inside the monadic wrapper when it is in it's Some or Ok state without transforming the value inside. The most common use case for Inspect is to inspect the value inside the wrapper and log it's value.
More Side-Effects
There are side-effects specific to a Result<T, E>.
Nesting
You will inevitably find yourself in a situation where you have a monadic wrapper nested inside of a monadic wrapper. Use the below functions to remove a level of nesting at a time.
Flatten
Sometimes you will find yourself with an Option inside an Option or a Result inside of a Result. Use Flatten to remove a level of nesting in the monadic wrapper.
Removes one level of nesting from an Option<Option<T>>
Removes one level of nesting from an Result<Result<T, E>, E>
Transpose
Sometimes you will find yourself with a Result inside an Option or an Option inside of a Result . Use Transpose to convert between them when your business logic needs it.
Calling Transpose in this situation declares that a Result of None<int> is a valid outcome in our business rules.
Calling Transpose in this scenario declares that the absence of a tax amount is valid in our business rules.
Conversion
There may come a time where you have an Option<T> but you need a Result<T, E>. An Option<T> can be converted into a Result<T, E> and vice versa.
Last updated
Was this helpful?