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 Results 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 ofOkand leavingErrvalues 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 ofErrand leavingOkvalues 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
OkorErrrespecitively, or returns the provided default value. - mapOrElse and mapErrOrElse
applies the provided function to the contained value of
OkorErrrespectively, or applies the provided default fallback function to the contained value ofErrorOkrespectively.
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:
Optiongets a number of additional helpers. See: extensions.option.Ops- When using Scala 2.13 extensions.iterable_ops.Ops is available for
processing collections of
Results.
- 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 typeVUsed to convert a
Result[E, T]to a value of typeVThis 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.Resultis 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
Vto aResult[E, T]Used to convert a value of type
Vto aResult[E, T]This interface is leveraged by the Result.apply method and extensions.all.Ops.toResult.