package jsbrucker
Package Members
- package result
Error handling with the Result type.
Use Case
Error handling with the Result type.
Result
is a type used for returning and propagating errors. It is an disjoint union with the variants, Ok, representing success and containing a value, and Err, representing error and containing an error value.Functions should return
Result
whenever errors are expected and recoverable.For simplicity many examples make use of primitives such as
String
andInt
for the error type. It is recommended that in practice developers should try to make use of more structured types to allow for improved error handling. As opposed to relying on a stringly-typed interface or integer error codes.A simple function returning
Result
might be defined and used like so:>>> import dev.jsbrucker.result._ >>> sealed trait MajorVersion >>> object MajorVersion { ... case object V1 extends MajorVersion ... case object V2 extends MajorVersion ... } >>> sealed trait ParseError >>> object ParseError { ... case object InvalidHeaderLength extends ParseError ... case object UnsupportedVersion extends ParseError ... } >>> def parseMajorVersion(header: List[Int]): Result[ParseError, MajorVersion] = ... header.headOption match { ... case None => Err(ParseError.InvalidHeaderLength) ... case Some(1) => Ok(MajorVersion.V1) ... case Some(2) => Ok(MajorVersion.V2) ... case _ => Err(ParseError.UnsupportedVersion) ... } >>> val version = parseMajorVersion(List(1, 2, 3, 4)) >>> version match { ... case Ok(v) => "working with version: " + v.toString ... case Err(e) => "error parsing header: " + e.toString ... } working with version: V1
Pattern matching on
Result
s is clear and straightforward for simple cases, butResult
comes with some convenience methods that make working with it more succinct.>>> import dev.jsbrucker.result._ >>> val goodResult: Result[String, Int] = Ok(10); >>> val badResult: Result[String, Int] = Err("Some Error") // The `isOk` and `isErr` methods do what they say. >>> goodResult.isOk && !goodResult.isErr true >>> badResult.isErr && !badResult.isOk true // `map` replaces the `Ok` value of a `Result` with the result of the provided function >>> goodResult.map(_ + 1) Ok(11) // `map` leaves an `Err` value of a `Result` as it was, ignoring the provided function >>> badResult.map(_ - 1) Err(Some Error) // Use `andThen` to continue the computation. scala> goodResult.andThen(i => Ok(i == 11)) res0: Result[String, Boolean] = Ok(false) // Use `orElse` to handle the error. scala> badResult.orElse { | case "Anticipated Error" => Ok(0) | case "Some Error" => Err(true) | case _ => Err(false) | } res1: Result[Boolean, Int] = Err(true)
Method overview
In addition to working with pattern matching,
Result
provides a wide variety of different methods.Querying the variant
The isOk and isErr methods return
true
if theResult
isOk
orErr
, respectively.The isOkAnd and isErrAnd methods take in a predicate and return
true
if theResult
isOk
orErr
respectively, and the predicate returnstrue
when applied to the contained value.The contains and containsErr methods take in a value and return
true
if it matches the innerOk
orErr
value respectively.Transforming contained values
These methods transform
Result
toOption
:- err transforms
Result[E, T]
intoOption[E]
, mappingErr(e)
toSome(e)
andOk(v)
toNone
- ok transforms
Result[E, T]
intoOption[T]
, mappingOk(v)
toSome(v)
andErr(e)
toNone
- transposeOption transposes a
Result[E, Option[T]]
into anOption[Result[E, T]]
- transposeOptionErr transposes a
Result[Option[E], T]
into anOption[Result[E, T]]
This method transforms the contained value of the
Ok
variant:- map transforms
Result[E, T]
intoResult[E, U]
by applying the provided function to the contained value ofOk
and leavingErr
values unchanged
This method transforms the contained value of the
Err
variant:- mapErr transforms
Result[E, T]
intoResult[F, T]
by applying the provided function to the contained value ofErr
and leavingOk
values unchanged
These methods transform a
Result[E, T]
into a value of a possibly different typeU
:- mapOr and mapErrOr applies the
provided function to the contained value of
Ok
orErr
respecitively, or returns the provided default value. - mapOrElse and mapErrOrElse
applies the provided function to the contained value of
Ok
orErr
respectively, or applies the provided default fallback function to the contained value ofErr
orOk
respectively.
These methods transform
Result
toFuture
:- transposeFuture transposes a
Result[E, Future[T]]
into aFuture[Result[E, T]]
- transposeFutureErr transposes a
Result[Future[E], T]
into aFuture[Result[E, T]]
Extracting contained values
These methods extract the contained value in a
Result[E, T]
when it is theOk
variant. If theResult
isErr
:- expect panics with a provided custom message
- unwrap panics with a generic message
- unwrapOr returns the provided default value
- unwrapOrElse returns the result of evaluating the provided function
These methods extract the contained value in a
Result[E, T]
when it is theErr
variant. If theResult
isOk
:Boolean operators
These methods treat the
Result
as a boolean value, whereOk
acts liketrue
andErr
acts likefalse
. There are two categories of these methods: ones that take aResult
as input, and ones that take a function as input (to be lazily evaluated).The and and or methods take another
Result
as input, and produce aResult
as output. Theand
method can produce aResult[E, U]
value having a different inner typeU
thanResult[E, T]
. Theor
method can produce aResult[F, T]
value having a different error typeF
thanResult[E, T]
.method
self
input
output
and
Err(e)
(ignored)
Err(e)
and
Ok(x)
Err(d)
Err(d)
and
Ok(x)
Ok(y)
Ok(y)
or
Err(e)
Err(d)
Err(d)
or
Err(e)
Ok(y)
Ok(y)
or
Ok(x)
(ignored)
Ok(x)
The andThen and orElse methods take a function as input, and only evaluate the function when they need to produce a new value. The
andThen
method can produce aResult[E, U]
value having a different inner typeU
thanResult[E, T]
. TheorElse
method can produce aResult[F, T]
value having a different error typeF
thanResult[E, T]
.NOTE: flatMap is equivalent to
andThen
and it is provided for consistency with typical Scala conventions. Along those lines flatMapErr is equivalent toorElse
.method
self
function input
function result
output
andThen
Err(e)
(not provided)
(not evaluated)
Err(e)
andThen
Ok(x)
x
Err(d)
Err(d)
andThen
Ok(x)
x
Ok(y)
Ok(y)
orElse
Err(e)
e
Err(d)
Err(d)
orElse
Err(e)
e
Ok(y)
Ok(y)
orElse
Ok(x)
(not provided)
(not evaluated)
Ok(x)
Implicits
Extension methods are provided to facilitate conversion of several types to a
Result
. They can imported usingimport dev.jsbrucker.result.implicits._
- All types get some extension methods out of the box. This includes:
Option
gets a number of additional helpers. See: extensions.option.Ops- When using Scala 2.13 extensions.iterable_ops.Ops is available for
processing collections of
Result
s.
- Note
This documentation began as a derivative of the Rust Result<T, E> documentation
- err transforms