Converts this Or to an Or with the same Good type and a Bad type consisting of
One parameterized by this Or's Bad type.
Converts this Or to an Or with the same Good type and a Bad type consisting of
One parameterized by this Or's Bad type.
For example, invoking the accumulating method on an Int Or ErrorMessage would convert it to an
Int Or One[ErrorMessage]. This result type, because the Bad type is an Every, can be used
with the mechanisms provided in trait Accumulation to accumulate errors.
Note that if this Or is already an accumulating Or, the behavior of this accumulating method does not change.
For example, if you invoke accumulating on an Int Or One[ErrorMessage] you will be rewarded with an
Int Or One[One[ErrorMessage]].
this Good, if this Or is a Good; or this Bad value wrapped in a One if
this Or is a Bad.
Maps the given function to this Or's value if it is a Bad or returns this if it is a Good.
Maps the given function to this Or's value if it is a Bad or returns this if it is a Good.
the function to apply
if this is a Bad, the result of applying the given function to the contained value wrapped in a Bad,
else this Good is returned
Returns true if this Or is a Good and the predicate p returns true when applied to this Good's value.
Returns true if this Or is a Good and the predicate p returns true when applied to this Good's value.
Note: The exists method will return the same result as forall if this Or is a Good, but the opposite
result if this Or is a Bad.
the predicate to apply to the Good value, if this is a Good
the result of applying the passed predicate p to the Good value, if this is a Good, else false
Returns this Or if either 1) it is a Bad or 2) it is a Good and applying the validation function f to this
Good's value returns Pass; otherwise,
returns a new Bad containing the error value contained in the Fail resulting from applying the validation
function f to this Good's value.
Returns this Or if either 1) it is a Bad or 2) it is a Good and applying the validation function f to this
Good's value returns Pass; otherwise,
returns a new Bad containing the error value contained in the Fail resulting from applying the validation
function f to this Good's value.
For examples of filter used in for expressions, see the main documentation for trait
Validation.
the validation function to apply
a Good if this Or is a Good that passes the validation function, else a Bad.
Returns the given function applied to the value contained in this Or if it is a Good,
or returns this if it is a Bad.
Returns the given function applied to the value contained in this Or if it is a Good,
or returns this if it is a Bad.
the function to apply
if this is a Good, the result of applying the given function to the contained value wrapped in a Good,
else this Bad is returned
Folds this Or into a value of type V by applying the given gf function if this is
a Good else the given bf function if this is a Bad.
Folds this Or into a value of type V by applying the given gf function if this is
a Good else the given bf function if this is a Bad.
the function to apply to this Or's Good value, if it is a Good
the function to apply to this Or's Bad value, if it is a Bad
the result of applying the appropriate one of the two passed functions, gf or bf, to this Or's value
Returns true if either this Or is a Bad or if the predicate p returns true when applied
to this Good's value.
Returns true if either this Or is a Bad or if the predicate p returns true when applied
to this Good's value.
Note: The forall method will return the same result as exists if this Or is a Good, but the opposite
result if this Or is a Bad.
the result of applying the passed predicate p to the Good value, if this is a Good, else true
Applies the given function f to the contained value if this Or is a Good; does nothing if this Or
is a Bad.
Applies the given function f to the contained value if this Or is a Good; does nothing if this Or
is a Bad.
the function to apply
Returns the Or's value if it is a Good or throws NoSuchElementException if it is a Bad.
Returns the Or's value if it is a Good or throws NoSuchElementException if it is a Bad.
the contained value if this is a Good
if this is a Bad
Returns, if this Or is Good, this Good's value; otherwise returns the result of evaluating default.
Returns, if this Or is Good, this Good's value; otherwise returns the result of evaluating default.
the default expression to evaluate if this Or is a Bad
the contained value, if this Or is a Good, else the result of evaluating the given default
Maps the given function to this Or's value if it is a Good or returns this if it is a Bad.
Maps the given function to this Or's value if it is a Good or returns this if it is a Bad.
the function to apply
if this is a Good, the result of applying the given function to the contained value wrapped in a Good,
else this Bad is returned
Returns this Or if it is a Good, otherwise returns the result of evaluating the passed alternative.
Returns this Or if it is a Good, otherwise returns the result of evaluating the passed alternative.
the alternative by-name to evaluate if this Or is a Bad
this Or, if it is a Good, else the result of evaluating alternative
Maps the given function to this Or's value if it is a Bad, transforming it into a Good, or returns
this if it is already a Good.
Maps the given function to this Or's value if it is a Bad, transforming it into a Good, or returns
this if it is already a Good.
the function to apply
if this is a Bad, the result of applying the given function to the contained value wrapped in a Good,
else this Good is returned
Maps the given function to this Or's value if it is a Bad, returning the result, or returns
this if it is already a Good.
Maps the given function to this Or's value if it is a Bad, returning the result, or returns
this if it is already a Good.
the function to apply
if this is a Bad, the result of applying the given function to the contained value,
else this Good is returned
Returns an Or with the Good and Bad types swapped: Bad becomes Good and Good
becomes Bad.
Returns an Or with the Good and Bad types swapped: Bad becomes Good and Good
becomes Bad.
Here's an example:
scala> val lyrics = Bad("Hey Jude, don't make it bad. Take a sad song and make it better.")
lyrics: org.scalactic.Bad[Nothing,String] =
Bad(Hey Jude, don't make it bad. Take a sad song and make it better.)scala> lyrics.swap
res12: org.scalactic.Or[String,Nothing] =
Good(Hey Jude, don't make it bad. Take a sad song and make it better.)
Now that song will be rolling around in your head all afternoon. But at least it is a good song (thanks to swap).
if this Or is a Good, its Good value wrapped in a Bad; if this Or is
a Bad, its Bad value wrapped in a Good.
Returns an Either: a Right containing the Good value, if this is a Good; a Left
containing the Bad value, if this is a Bad.
Returns an Either: a Right containing the Good value, if this is a Good; a Left
containing the Bad value, if this is a Bad.
Note that values effectively “switch sides” when convering an Or to an Either. If the type of the
Or on which you invoke toEither is Or[Int, ErrorMessage] for example, the result will be an
Either[ErrorMessage, Int]. The reason is that the convention for Either is that Left is used for “bad”
values and Right is used for “good” ones.
this Good value, wrapped in a Right, or this Bad value, wrapped in a Left.
Returns a Some containing the Good value, if this Or is a Good, else None.
Returns a Some containing the Good value, if this Or is a Good, else None.
the contained “good” value wrapped in a Some, if this Or is a Good; None
if this Or is a Bad.
Returns an immutable IndexedSeq containing the Good value, if this Or is a Good, else an empty
immutable IndexedSeq.
Returns an immutable IndexedSeq containing the Good value, if this Or is a Good, else an empty
immutable IndexedSeq.
the contained “good” value in a lone-element Seq if this Or is a Good; an empty Seq if
this Or is a Bad.
Returns a Try: a Success containing the
Good value, if this is a Good; a Failure
containing the Bad value, if this is a Bad.
Returns a Try: a Success containing the
Good value, if this is a Good; a Failure
containing the Bad value, if this is a Bad.
Note: This method can only be called if the Bad type of this Or is a subclass
of Throwable (or Throwable itself).
Note that values effectively “switch sides” when converting an Or to an Either. If the type of the
Or on which you invoke toEither is Or[Int, ErrorMessage] for example, the result will be an
Either[ErrorMessage, Int]. The reason is that the convention for Either is that Left is used for “bad”
values and Right is used for “good” ones.
this Good value, wrapped in a Right, or this Bad value, wrapped in a Left.
Transforms this Or by applying the function gf to this Or's Good value if it is a Good,
or by applying bf to this Or's Bad value if it is a Bad.
Transforms this Or by applying the function gf to this Or's Good value if it is a Good,
or by applying bf to this Or's Bad value if it is a Bad.
the function to apply to this Or's Good value, if it is a Good
the function to apply to this Or's Bad value, if it is a Bad
the result of applying the appropriate one of the two passed functions, gf or bf, to this Or's value
Indicates whether this Or is a Bad
Indicates whether this Or is a Bad
true if this Or is a Bad, false if it is a Good.
Indicates whether this Or is a Good
Indicates whether this Or is a Good
true if this Or is a Good, false if it is a Bad.
Currently just forwards to filter, and therefore, returns the same result.
Represents a value that is one of two possible types, with one type being “good” and the other “bad.”
An
Orwill either be a “good” value wrapped in an instance ofGoodor a “bad” value wrapped in an instance ofBad.The motivation for
OrOrdiffers from Scala'sEithertype in thatEithertreats both itsLeftandRightalternatives in an identical manner, whereasOrtreats its two alternatives differently: it favorsGoodoverBad. Because of this, it is more convenient to work withOrs when you prefer one alternative over the other; for example, if one alternative represents a valid result and another represents an error.To illustrate, imagine you want to create instances this
Personclass from user input strings:You might write a method that parses the name from user input string and returns an
Option[String]:Noneif the string is empty or blank, else the trimmed string wrapped in aSome:You might also write a method that parses the age from user input string and returns an
Option[Int]:Noneif either the string is not a valid integer or it is a negative integer, else the string converted to an integer wrapped in aSome:With these building blocks you could write a method that parses name and age input strings and returns either a
Person, wrapped in aSome, orNoneif either the name or age, or both, was invalid:Here are some examples of invoking
parsePerson:Now imagine you want to give an error message back if the user's input is invalid. You might rewrite the parsing methods to return an
Eitherinstead. In this case, the desired result is a valid name or age, which by convention should be placed on the right of theEither. The left will be aStringerror message. Here's the newparseNamefunction, which returns anEither[String, String]:And here's the new
parseAgefunction, which returns anEither[String, Int]:The new
parsePersonmethod will return anEither[String, Person]:Note that
Eitherrequires you to add.rightat the end of each generator in theforexpression. Although the convention is to place the valid result on the right, you must explicitly (and repetitively) indicate that you've done so by transforming theEitherto aRightProjectionby invoking.rightat each step. Given this implementation, theparsePersonmethod will now short-circuit at the first sign of trouble (as it did when we used anOption), but you now get the first error message returned in aLeft. Here are some examples:An
Eitherwith “attitude”Because
Ordeclares one alternative to be “good” and the other “bad,” it is more convenient thanEitherin this kind of situation. One difference to note withOris that theGoodalternative is on the left,Badon the right. The reason is thatOris designed to be written using infix notation, and placing the “happy path” first is more readable. For example, instead of writing:Or[Int, ErrorMessage]You can write:
Here's how the
parseNamemethod might be written using anOr, whereErrorMessageis a type alias forStringdeclared in theorg.scalacticpackage object:You can think of the
StringOrErrorMessageresult type like this:Here's how the
parseAgemethod might be written:Given these implementations, here's how you'd write the
parsePersonmethod:Because of
Or's attitude, you need not write.goodat the end of each generator.Orwill keep going so long as each step produces aGood, short circuiting at the first sign of aBad. Here are a few invocations of thisparsePersonmethod:Accumulating errors with
OrAnother difference between
OrandEitheris thatOrenables you to accumulate errors if theBadtype is anEvery. AnEveryis similar to aSeqin that it contains ordered elements, but different fromSeqin that it cannot be empty. AnEveryis either aOne, which contains one and only one element, or aMany, which contains two or more elements.Note: an
OrwhoseBadtype is anEvery, or one of its subtypes, is called an “accumulatingOr.”To rewrite the previous example so that errors can be accumulated, you need first to return an
Everyas theBadtype. Here's how you'd change theparseNamemethod:Because
parseNamewill either return a valid nameStringwrapped in aGood, or one error message, wrapped in aBad, you would write theBadtype asOne[ErrorMessage]. The same is true forparseAge:Because a
forexpression short-circuits on the firstBadencountered, you'll need to use a different approach to write theparsePersonmethod. In this example, thewithGoodmethod from traitAccumulationwill do the trick:Trait
Accumulationoffers overloadedwithGoodmethods that take 1 to 22 accumulatingOrs, plus a function taking the same number of correspondingGoodvalues. In this example, if bothnameandageareGoods, thewithGoodmethod will pass the good nameStringand ageIntto thePerson(_, _)function, and return the resultingPersonobject wrapped in aGood. If eithernameandage, or both, areBad,withGoodwill return the accumulated errors in aBad.The result of
parsePerson, ifBad, will therefore contain either one or two error messages, i.e., the result will either be aOneor aMany. As a result, the result type ofparsePersonmust bePersonOrEvery[ErrorMessage]. Regardless of whether aBadresult contains one or two error messages, it will contain every error message. Here's some invocations of this accumulating version ofparsePerson:Note that in the last example, the
Badcontains an error message for both name and age.Other ways to accumulate errors
The
Accumlationtrait also enables other ways of accumulating errors.Using
combinedIf you have a collection of accumulating
Ors, for example, you can combine them into oneOrusingcombined, like this:Using
validatedByOr if you have a collection of values and a function that transforms that type of value into an accumulating
Ors, you can validate the values using the function usingvalidatedBy, like this:Using
zipYou can also zip two accumulating
Ors together. If both areGood, you'll get aGoodtuple containin both originalGoodvalues. Otherwise, you'll get aBadcontaining every error message. Here are some examples:Using
whenIn addition, given an accumlating
Or, you can pass one or more validation functions towhenon theOrto submit thatOrto further scrutiny. A validation function accepts aGoodtype and returns aValidation[E], whereEis the type in theEveryin theBadtype. For anIntOrOne[ErrorMessage], for example the validation function type would beInt=>Validation[ErrorMessage]. Here are a few examples:If the
Oron which you callwhenis alreadyBad, you get the same (Bad)Orback, because noGoodvalue exists to pass to the valiation functions:If the
Oron which you callwhenisGood, and also passes all the validation functions (i.e., the all returnNone), you again get the sameOrback, but this time, aGoodone:If one or more of the validation functions fails, however, you'll get a
Badback contining every error. Here are some examples:Note that you can use
whento accumulate errors in aforexpression involving an accumulatingOr, like this:Much ado about
NothingBecause
Orhas two types, but each of its two subtypes only takes a value of one or the other type, the Scala compiler will inferNothingfor the unspecified type:Often
Nothingwill work fine, as it will be widened as soon as the compiler encounters a more specific type. Sometimes, however, you may need to specify it. In such situations you can use this syntax:If you want to specify both types, because you don't like the inferred type, you can do so like this:
But you may find the code is clearer if you instead use a type ascription, like this:
Note: The
Orhierarchy was inspired in part by the disjoint union (\/) andValidationtypes ofscalaz, theProcessResulttype of Typesafe Activator, and theResulttype of ScalaKittens.