sealed trait Result[+E, +A] extends Product with Serializable
Represents a value of one of two states:
It is similar to Either or a more generic Try.
Motivation
Scalas Either is unbiased, meaning it treats its two sides equally and
requires one to explicitly state on which side one wants to work on.
More often that not, one side is representing the error or invalid part and
one side representing the success or valid part.
Result sets the invalid side on the left and the valid side on the right
and assumes, that one wants to primarily work on the right/valid side.
This is similar to Try, which fixes the invalid type to Throwable.
Example:
import validation._, Result._ case class Person(name: String) def validateName(input: String): Result[String, String] = if (input.trim.isEmpty) invalid("name must not be empty") else valid(input) List("Bernd", "").map(validateName(_).map(Person.apply)) // List[Result[String,Person]] = List( // Valid(Person(Bernd)), // Invalid(name must not be empty) // )
Both, Either and Try, cannot accumulate errors, but are typically
aborting with the first failure, making them disadvantageous for parsing and
validating data on system boundaries.
For example, parsing a JSON data structure can lead to multiple issues and
it is good measure to report as many errors as you can back to the user.
With Either or Try, only one error at the time gets reported, leading
to the user to submit a fixed version only to encounter, that they have to
fixed yet another error.
Result can accumulate errors and thus allows to report as many of them as
possible. There are multiple ways to combine two or more Results, for a
detailed description, see their respective documentation.
Example:
import validation._, Result._ case class Person(name: String, age: Int) def validateName(input: String): Result[String, String] = if (input.trim.isEmpty) invalid("name must not be empty") else valid(input) def validateAge(input: String): Result[String, Int] = { val ageVal = if (input.trim.isEmpty) invalid("age must not be empty") else Result.parseInt(input).invalidMap(_.getMessage) ageVal.filter(_ >= 0, "age must be positive") } def parsePerson(inName: String, inAge: String): Result[List[String], Person] = { val nameVal = validateName(inName).invalidMap(List(_)) val ageVal = validateAge(inAge).invalidMap(List(_)) (nameVal and ageVal) apply Person } val inputs = List( ("Bernd", "42"), ("Ralle", ""), ("Ronny", "foo"), ("", "-1337") ) inputs.map((parsePerson _).tupled) // List[Result[List[String],Person]] = List( // Valid(Person(Bernd,42)), // Invalid(List(age must not be empty)), // Invalid(List(For input string: "foo")), // Invalid(List(name must not be empty, age must be positive)) // )
- E
the
Invalidtype- A
the
Validtype
- Since
0.1.0
- Alphabetic
- By Inheritance
- Result
- Serializable
- Serializable
- Product
- Equals
- Any
- Hide All
- Show All
- Public
- All
Abstract Value Members
Concrete Value Members
-
final
def
!=(arg0: Any): Boolean
- Definition Classes
- Any
-
final
def
##(): Int
- Definition Classes
- Any
-
def
==(other: Result[E, A]): Boolean
[use case]
[use case] Full Signaturedef ==[EE >: E, AA >: A](other: Result[EE, AA])(implicit EE: Equiv[EE], AA: Equiv[AA]): Boolean
-
final
def
==(arg0: Any): Boolean
- Definition Classes
- Any
-
def
and[B](other: Result[E, B]): Ap2[E, A, B]
[use case] Combines two
Results in a builder, eventually accumulating invalids.[use case]Combines two
Results in a builder, eventually accumulating invalids.This is the Applicative Builder of the valid result.
- B
the other valid type
- other
the other
Resultthis one should be combined with- returns
a builder to eventually apply two
Results
-
def
append(other: Result[E, A]): Result[E, A]
[use case]
[use case] Full Signaturedef append[EE >: E, AA >: A](other: ⇒ Result[EE, AA]): Result[EE, NonEmptyVector[AA]]
-
def
apply[B](f: Result[E, (A) ⇒ B]): Result[E, B]
[use case] Applies a function in the
Resultcontext to the valid value, accumulating invalids.[use case]Applies a function in the
Resultcontext to the valid value, accumulating invalids.This is the Applicative Functor of the valid Result.
- B
the resulting valid type
- f
the function in the
Resultcontext- returns
the valid result if
thisandfare valid or invalid if one of each is invalid or both invalid values accumulated
-
def
as[B](x: ⇒ B): Result[E, B]
Sets the valid value to
xand discards the previous value if this is a valid Result.Sets the valid value to
xand discards the previous value if this is a valid Result.- B
the resulting valid type
- x
the new valid value
- returns
the result with the valid value set to
x
- Since
0.2.0
-
final
def
asInstanceOf[T0]: T0
- Definition Classes
- Any
-
def
bimap[EE, AA](fe: (E) ⇒ EE, fa: (A) ⇒ AA): Result[EE, AA]
Transforms the value of this
Result.Transforms the value of this
Result.- EE
the resulting invalid type
- AA
the resulting valid type
- fe
the function to transform an invalid value
- fa
the function to transform a valid value
- returns
the result with either the valid or invalid value transformed
-
def
compare(other: Result[E, A]): Int
[use case]
[use case] Full Signaturedef compare[EE >: E, AA >: A](other: Result[EE, AA])(implicit EE: Ordering[EE], AA: Ordering[AA]): Int
-
def
contains(x: A): Boolean
[use case] Tests for membership on the valid
Result[use case]Tests for membership on the valid
Result- returns
trueif thisResulthasxas valid value
Full Signaturedef contains[AA >: A](x: ⇒ AA): Boolean
-
def
equals(arg0: Any): Boolean
- Definition Classes
- Any
-
def
exists(p: (A) ⇒ Boolean): Boolean
- returns
trueif thisResultis valid and satisfies the predicatep
-
def
filter(p: (A) ⇒ Boolean, ifEmpty: ⇒ E): Result[E, A]
[use case] Filters the valid value of this
Result.[use case]Filters the valid value of this
Result. Full Signaturedef filter[EE >: E](p: (A) ⇒ Boolean, ifEmpty: ⇒ EE): Result[EE, A]
-
def
flatMap[B](f: (A) ⇒ Result[E, B]): Result[E, B]
[use case] Continues validation with the provided function if this is a valid
Result.[use case]Continues validation with the provided function if this is a valid
Result.flatMapdoes not accumulate errors. If you want to do so, useandinstead.This is the Monadic Bind through the valid value.
- B
the resulting valid type
- f
the function to continue with
- returns
the result of applying
fover the valid value in theResultcontext
-
def
fold[B](fe: (NonEmptyVector[E]) ⇒ B, fa: (A) ⇒ B): B
Folds this
Resultinto a value by applying the first function if this is aInvalidor the second function if this is aValid.Folds this
Resultinto a value by applying the first function if this is aInvalidor the second function if this is aValid.This is the Catamorphism.
- B
the resulting type
- fe
the function to apply in the invalid case
- fa
the function to apply in the valid case
- returns
the result of one of the two functions
-
def
foldLeft[B](b: B)(f: (B, A) ⇒ B): B
A left fold over the valid value.
A left fold over the valid value.
- B
the resulting type
- b
the initial accumulator
- f
reducer function of the accumulator and the valid value
- returns
bif this isInvalid, otherwise the result of applyingf
- See also
-
def
foldRight[B](b: B)(f: (A, B) ⇒ B): B
A right fold over the valid value.
A right fold over the valid value.
- B
the resulting type
- b
the initial accumulator
- f
reducer function of the valid value and the accumulator
- returns
bif this isInvalid, otherwise the result of applyingf
- See also
-
def
forall(p: (A) ⇒ Boolean): Boolean
- returns
trueif thisResultis invalid or the valid value satisfies the predicatep
-
def
getEither: A
[use case]
[use case] Full Signaturedef getEither[AA >: A](implicit ev: <:<[E, AA]): AA
-
def
getOrElse(a: A): A
[use case]
[use case] Full Signaturedef getOrElse[AA >: A](aa: ⇒ AA): AA
-
def
hashCode(): Int
- Definition Classes
- Any
-
def
invalid[B](fe: (NonEmptyVector[E]) ⇒ B)(fa: (A) ⇒ B): B
Curried fold that starts with the invalid part.
-
def
invalidMap[F](f: (E) ⇒ F): Result[F, A]
Maps over the invalid value of this
Result.Maps over the invalid value of this
Result.This is the Functor over the invalid side.
- F
the resulting invalid type
- f
the function to apply if this
Resultis invalid- returns
the result of the function application in the
Resultcontext
-
final
def
isInstanceOf[T0]: Boolean
- Definition Classes
- Any
-
def
isInvalid: Boolean
- returns
trueif this is an invalidResult
-
def
isValid: Boolean
- returns
trueif this is a validResult
-
def
map[B](f: (A) ⇒ B): Result[E, B]
Maps over the valid value of this
Result.Maps over the valid value of this
Result.This is the Functor over the valid side.
- B
the resulting valid type
- f
the function to apply if this
Resultis valid- returns
the result of the function application in the
Resultcontext
-
def
merge(other: Result[E, A]): Result[E, A]
[use case]
[use case] Full Signaturedef merge[EE >: E, AA >: A](other: ⇒ Result[EE, AA]): Result[EE, NonEmptyVector[AA]]
-
def
nev: Result[E, NonEmptyVector[A]]
- returns
Result where the valid value is wrapped in a NonEmptyVector
- Since
0.2.0
-
def
orElse(other: Result[E, A]): Result[E, A]
[use case]
-
def
productIterator: Iterator[Any]
- Definition Classes
- Product
-
def
productPrefix: String
- Definition Classes
- Product
-
def
recover(f: (E) ⇒ A): Result[E, A]
[use case] Transforms an invalid Result into a valid one.
[use case]Transforms an invalid Result into a valid one.
- f
the function to transform an invalid value into a valid one
- returns
a result that is always valid
Full Signaturedef recover[AA >: A](f: (E) ⇒ AA): Result[E, AA]
-
def
recoverAll(f: (NonEmptyVector[E]) ⇒ A): Result[E, A]
[use case] Transforms an invalid Result into a valid one.
[use case]Transforms an invalid Result into a valid one.
- f
the function to transform all invalid values into a valid one
- returns
a result that is always valid
Full Signaturedef recoverAll[AA >: A](f: (NonEmptyVector[E]) ⇒ AA): Result[E, AA]
-
def
recoverWith[F](f: (E) ⇒ Result[F, A]): Result[F, A]
[use case] Continues validation with the provided function if this is an invalid
Result.[use case]Continues validation with the provided function if this is an invalid
Result.This is the Monadic Bind through the invalid value.
- F
the resulting invalid type
- f
the function to continue with
- returns
the result of applying
fover the invalid value in theResultcontext
- def swap: Result[A, NonEmptyVector[E]]
- def swapped[EE, AA](f: (Result[A, NonEmptyVector[E]]) ⇒ Result[AA, NonEmptyVector[EE]]): Result[EE, NonEmptyVector[AA]]
- def toEither: Either[NonEmptyVector[E], A]
- def toList: List[A]
-
def
toOption: Option[A]
- returns
a
scala.Option
- def toSeq: Seq[A]
-
def
toSet: Set[A]
[use case]
[use case] Full Signaturedef toSet[AA >: A]: Set[AA]
- def toStream: Stream[A]
-
def
toString(): String
- Definition Classes
- Any
-
def
toTry: Try[A]
[use case]
[use case] Full Signaturedef toTry(implicit ev: <:<[E, Throwable]): Try[A]
- def toVector: Vector[A]
-
def
valid[B](fa: (A) ⇒ B)(fe: (NonEmptyVector[E]) ⇒ B): B
Curried fold that starts with the valid part.
-
def
valueOr(x: (E) ⇒ A): A
[use case]
[use case] Full Signaturedef valueOr[AA >: A](x: (NonEmptyVector[E]) ⇒ AA): AA
-
def
void: Result[E, Unit]
Discards the valid value if this is a valid Result.
Discards the valid value if this is a valid Result.
- returns
the result with the valid value set to Unit
- Since
0.2.0
-
def
zip[B](b: Result[E, B]): Result[E, (A, B)]
[use case] Combines two
Resultby zipping their valid values together, accumulating errors.
Inherited from Serializable
Inherited from Serializable
Inherited from Product
Inherited from Equals
Inherited from Any
Accessors and Extractors
Methods to access or extract a value from this Result.
Transformers
Methods to transform the value of this Result.
Testers
Methods to test the value of this Result for some properties.
Translators
Methods to translate this Result into a different structure.
Combinators
Methods to combine multiple Results.