Either<L, R> class
abstract
Author: Petrus Nguyễn Thái Học.
Either is a type that represents either Right (usually represent a "desired" value) or Left (usually represent a "undesired" value or error value).
Elm Result. Haskell Data.Either. Rust Result.
In day-to-day programming, it is fairly common to find ourselves writing functions that can fail.
For instance, querying a service may result in a connection issue, or some unexpected JSON
response.
To communicate these errors, it has become common practice to throw exceptions; however, exceptions are not tracked in any way, shape, or form by the compiler. To see what kind of exceptions (if any) a function may throw, we have to dig through the source code. Then, to handle these exceptions, we have to make sure we catch them at the call site. This all becomes even more unwieldy when we try to compose exception-throwing procedures.
double throwsSomeStuff(int i) => throw UnimplementedError();
String throwsOtherThings(double d) => throw UnimplementedError();
List<int> moreThrowing(String s) => throw UnimplementedError();
List<int> magic(int i) => moreThrowing( throwsOtherThings( throwsSomeStuff(i) ) );
Assume we happily throw exceptions in our code. Looking at the types of the functions above,
any could throw a number of exceptions -- we do not know. When we compose, exceptions from any of the constituent
functions can be thrown. Moreover, they may throw the same kind of exception
(e.g., ArgumentError
) and, thus, it gets tricky tracking exactly where an exception came from.
How then do we communicate an error? By making it explicit in the data type we return.
Either
Either
is used to short-circuit a computation upon the first error.
By convention, the right side of an Either
is used to hold successful values.
Because Either
is right-biased, it is possible to define a Monad
instance for it.
Since we only ever want the computation to continue in the case of Right (as captured by the right-bias nature),
we fix the left type parameter and leave the right one free. So, the map and flatMap methods are right-biased.
- Implementers
- Available Extensions
- Annotations
-
- @immutable
- @sealed
Constructors
-
Either.binding(@monadComprehensions R block(EitherEffect<
L> effect)) -
Monad comprehension.
Syntactic sugar do-notation.
Although using flatMap openly often makes sense, many programmers prefer a syntax
that mimics imperative statements (called
do-notation
inHaskell
,perform-notation
inOCaml
,computation expressions
inF#
, andfor comprehension
inScala
). This is only syntactic sugar that disguises a monadic pipeline as a code block.factory -
Either.catchError(ErrorMapper<
L> errorMapper, R block()) -
Evaluates the specified
block
and wrap the result in a Right.factory - Either.left(L left)
-
Create a Left.
constfactory
- Either.right(R right)
-
Create a Right.
constfactory
Properties
- hashCode → int
-
The hash code for this object.
no setterinherited
- isLeft → bool
-
Returns
true
if this is a Left,false
otherwise. Used only for performance instead of fold.no setter - isRight → bool
-
Returns
true
if this is a Right,false
otherwise. Used only for performance instead of fold.no setter - runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
all(
bool predicate(R value)) → bool -
Returns
true
if Left or returns the result of the application of the given predicate to the Right value. -
bimap<
C, D> ({required C leftOperation(L value), required D rightOperation(R value)}) → Either< C, D> - Map over Left and Right of this Either
-
exists(
bool predicate(R value)) → bool -
Returns
false
if Left or returns the result of the application of the givenpredicate
to the Right value. -
findOrNull(
bool predicate(R value)) → R? -
Returns the Right.value matching the given
predicate
, ornull
if this is a Left or Right.value does not match. -
flatMap<
C> (Either< L, C> f(R value)) → Either<L, C> - Binds the given function across Right.
-
fold<
C> ({required C ifLeft(L value), required C ifRight(R value)}) → C -
Applies
ifLeft
if this is a Left orifRight
if this is a Right. -
foldLeft<
C> (C initial, C rightOperation(C acc, R element)) → C -
If this is a Right, applies
ifRight
withinitial
and Right.value. Returnsinitial
otherwise. -
getOrElse(
R defaultValue()) → R - Returns the value from this Right or the given argument if this is a Left.
-
getOrHandle(
R defaultValue(L value)) → R - Returns the value from this Right or allows clients to transform the value of Left to the final result.
-
handleError(
R f(L value)) → Either< L, R> - Handle any error, potentially recovering from it, by mapping it to an Either value.
-
handleErrorWith<
C> (Either< C, R> f(L value)) → Either<C, R> - Handle any error, potentially recovering from it, by mapping it to an Either value.
-
map<
C> (C f(R value)) → Either< L, C> -
The given function is applied if this is a
Right
. -
mapLeft<
C> (C f(L value)) → Either< C, R> -
The given function is applied if this is a
Left
. -
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
orNull(
) → R? -
Returns the Right's value if it exists, otherwise
null
. -
redeem<
C> ({required C leftOperation(L value), required C rightOperation(R value)}) → Either< L, C> -
Redeem an Either to an Either by resolving the error or mapping the value
R
toC
. -
redeemWith<
C, D> ({required Either< C, D> leftOperation(L value), required Either<C, D> rightOperation(R value)}) → Either<C, D> -
Redeem an Either to an Either by resolving the error
or mapping the value
R
toC
with an Either. -
swap(
) → Either< R, L> -
If this is a
Left
, then return the left value inRight
or vice versa. -
tap(
void f(R value)) → Either< L, R> - The given function is applied as a fire and forget effect if this is a Right. When applied the result is ignored and the original Either value is returned.
-
tapLeft(
void f(L value)) → Either< L, R> - The given function is applied as a fire and forget effect if this is a Left. When applied the result is ignored and the original Either value is returned.
-
toString(
) → String -
A string representation of this object.
inherited
-
when<
C> ({required C ifLeft(Left< L, R> left), required C ifRight(Right<L, R> right)}) → C -
Applies
ifLeft
if this is a Left orifRight
if this is a Right.
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited
Static Methods
-
catchFutureError<
L, R> (ErrorMapper< L> errorMapper, FutureOr<R> block()) → Future<Either< L, R> > -
Evaluates the specified
block
and wrap the result in a Right. -
catchStreamError<
L, R> (ErrorMapper< L> errorMapper, Stream<R> stream) → Stream<Either< L, R> > - Transforms data events to Rights and error events to Lefts.
-
fromNullable<
R extends Object> (R? value) → Either< void, R> -
Returns a Right if
value
is notnull
, otherwise a Left containingnull
. -
futureBinding<
L, R> (FutureOr< R> block(EitherEffect<L> effect)) → Future<Either< L, R> > -
Monad comprehension.
Syntactic sugar do-notation.
Although using flatMap openly often makes sense, many programmers prefer a syntax
that mimics imperative statements (called
do-notation
inHaskell
,perform-notation
inOCaml
,computation expressions
inF#
, andfor comprehension
inScala
). This is only syntactic sugar that disguises a monadic pipeline as a code block. -
parSequenceN<
L, R> (Iterable< Future< functions, int? n) → Future<Either< Function()>L, R> >Either< L, BuiltList< >R> > - TODO(parSequenceN)
-
parTraverseN<
L, R, T> (Iterable< T> values, Future<Either< Function() mapper(T value), int? n) → Future<L, R> >Either< L, BuiltList< >R> > - TODO(parTraverseN)
-
sequence<
L, R> (Iterable< Either< values) → Either<L, R> >L, BuiltList< R> > - Sequences all Either values. If one of them is a Left, then it will short-circuit the operation, and returning the first encountered Left.
-
traverse<
L, R, T> (Iterable< T> values, Either<L, R> mapper(T value)) → Either<L, BuiltList< R> > -
Traverses the
values
iterable and runsmapper
on each element.