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._
caseclass 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._
caseclass 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))// )
Represents a value of one of two states:
Valid(a)
Invalid(e)
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 toTry
, which fixes the invalid type toThrowable
.Example:
Both,
Either
andTry
, 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. WithEither
orTry
, 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 moreResult
s, for a detailed description, see their respective documentation.Example:
the
Invalid
typethe
Valid
type0.1.0