package result
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
and
Int
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,
but Result
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
the Result
is Ok
or Err
, respectively.
The isOkAnd and isErrAnd methods take
in a predicate and return true
if the Result
is Ok
or Err
respectively, and the predicate returns true
when applied to the contained
value.
The contains and containsErr
methods take in a value and return true
if it matches the inner Ok
or
Err
value respectively.
Transforming contained values
These methods transform Result
to Option
:
- 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 type U
:
- 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
to Future
:
- 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 the
Ok
variant. If the Result
is Err
:
- 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 the
Err
variant. If the Result
is Ok
:
Boolean operators
These methods treat the Result
as a boolean value, where Ok
acts like
true
and Err
acts like false
. There are two categories of these
methods: ones that take a Result
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 a Result
as output. The and
method can produce a
Result[E, U]
value having a different inner type U
than Result[E, T]
.
The or
method can produce a Result[F, T]
value having a different error
type F
than Result[E, T]
.
method | self | input | output |
---|---|---|---|
| | (ignored) | |
| | | |
| | | |
| | | |
| | | |
| | (ignored) | |
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 a Result[E, U]
value having
a different inner type U
than Result[E, T]
. The orElse
method can
produce a Result[F, T]
value having a different error type F
than
Result[E, T]
.
NOTE: flatMap is equivalent to andThen
and it is
provided for consistency with typical Scala conventions. Along those lines
flatMapErr is equivalent to orElse
.
method | self | function input | function result | output |
---|---|---|---|---|
| | (not provided) | (not evaluated) | |
| | | | |
| | | | |
| | | | |
| | | | |
| | (not provided) | (not evaluated) | |
Implicits
Extension methods are provided to facilitate conversion of several types to
a Result
. They can imported using import 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
- Alphabetic
- By Inheritance
- result
- AnyRef
- Any
- Hide All
- Show All
- Public
- All
Type Members
-
final
case class
Err[+E, +T](e: E) extends AnyVal with Result[E, T] with Product with Serializable
Contains the error value
-
trait
FromResult[-E, -T, +V] extends AnyRef
Used to convert a
Result[E, T]
to a value of typeV
Used to convert a
Result[E, T]
to a value of typeV
This interface is leveraged by the Result.to method.
-
final
case class
Ok[+E, +T](v: T) extends AnyVal with Result[E, T] with Product with Serializable
Contains the success value
-
sealed
trait
Result[+E, +T] extends Any
A Rust
Result<T, E>
inspired interface for handling results.A Rust
Result<T, E>
inspired interface for handling results.Result
is a type that represents either success (Ok) or failure (Err). See the package documentation for details. -
trait
ToResult[+E, +T, -V] extends AnyRef
Used to convert a value of type
V
to aResult[E, T]
Used to convert a value of type
V
to aResult[E, T]
This interface is leveraged by the Result.apply method and extensions.all.Ops.toResult.