steps.result

package steps.result

Members list

Type members

Classlikes

object Conversions

Defines possible implicit conversions into Result from various types.

Defines possible implicit conversions into Result from various types.

// for conversions from `Either` and `scala.util.Try`
import Conversions.FromScala.given
// for conversions from `Option` into `Result[T, ResultIsErrException]`
import Conversions.FromOption.given
// for implicit lifting from any type `T` into `Result[T, Nothing]`
import Conversions.Lift.given

Additionally, import Conversions.Compat.given provides an instance of Conversion[T, T] to aid with using Result.eval functions.

import Conversions.Compat.given

val ok: Result[Int, String] = Ok(3)
Result[Int, Any]:
 ok.? // Ok, Conversion[String, Any] is present

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
enum Result[+T, +E] extends IterableOnce[T]

Represents either a success value of type T or an error of type E. It can be used when expecting results that have errors that should be inspected by the caller. For this, Result have a precise error type parameter.

Represents either a success value of type T or an error of type E. It can be used when expecting results that have errors that should be inspected by the caller. For this, Result have a precise error type parameter.

To create one, directly use one of the variant constructors Ok or Err, or start a computation scope with Result.apply:

extension[T] (it: IterableOnce[T])
 def tryMap[U, E](f: T => Result[U, E]): Result[Seq[U], E] =
   Result:
     it.iterator.map(f(_).ok) // shorts-circuit on the first Err and returns

Tail-recursive functions can be implemented by using eval.break:

extension[T] (seq: Seq[T])
 @scala.annotation.tailrec
 def tryFoldLeft[U, E](init: U)(f: (U, T) => Result[U, E]) =
   Result:
     seq match
       case Seq() => init
       case Seq(h, t*) => eval.break(t.tryFoldLeft(f(init, h)))

// however, a much simpler implementation is
extension[T] (it: IterableOnce[T])
 def tryFoldLeft[U, E](init: U)(f: (U, T) => Result[U, E]) =
   Result:
     it.iterator.foldLeft(init)(f(_, _).ok)

Conversions from Option and Either are available in ScalaConverters (or implicitly through importing Conversions).

// from Option
val opt: Option[Int] = f()
val res1 = opt.okOr(Error.NotFound) // with explicit error
val res2 = opt.asResult // Result[Int, NoSuchElementException]
// to Option
val opt2 = res1.ok // returns Option[Int]

// from Either
val either: Either[E, T] = f()
val res = either.asResult // Result[T, E]
// to Either
val either2 = res.toEither

// from Try
val t: Try[T] = Try { /* ... */ }
val res = t.asResult // Result[T, Throwable]
// to Try
val t2 = res.toTry // Try[T], if error type is throwable
val t2 = Try { res.get } // Try[T], throws ResultIsErrException

Casual usage in a library where precise error reporting is preferred would consist of creating the Error type as an enum or an union type, aliasing the Result type with the correct error type, and using it as part of the function signature.

enum LibError:
 case A
 case B(inner: SomeError)
// or ...
type LibError = ErrorA.type | SomeError

type LibResult[+T] = Result[T, LibError]

object LibResult:
 import scala.util.boundary
 export Result.{apply as _, *}

 // override `apply` manually, to have it fix the Error type parameter.
 inline def apply[T](inline body: boundary.Label[LibResult[T]] => T) = Result.apply(body)

// in the library:
def ApiEndpoint(p: Int): LibResult[String] =
 LibResult:
   // ...

In end applications, prefer either:

  • directly matching over the Result, where precise errors need to be inspected.
  • in other cases, where tracing is wanted and error details are less important, prefer unwrapping the Result directly and catch the Result.ResultIsErrException at the top level to inspect the error details.

Attributes

Companion
object
Supertypes
trait Enum
trait Serializable
trait Product
trait Equals
trait IterableOnce[T]
class Object
trait Matchable
class Any
Show all
Known subtypes
class Ok[T]
class Err[E]
object Result

Attributes

Companion
enum
Supertypes
trait Sum
trait Mirror
class Object
trait Matchable
class Any
Self type
Result.type

Provides extension methods convert Scala API optional value containers into Result.

Provides extension methods convert Scala API optional value containers into Result.

By default, Result already provides conversions back into these containers through Result.ok, Result.toEither and Result.toTry.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type