Let's assume an object constructed using a builder pattern.
This builder pattern would contain a build
method focusing on fields validation and then on conversion to the targeted type.
This validation could be implemented using:
Either[FailureObject, TargetObject]
typeTry[TargetObject]
(new feature from Scala 2.10)Validation[FailureObject, TargetObject]
or ValidationNEL[FailureObject, TargetObject]
from scalaz libraryI read that one of the main advantages of Validation
over Either
type is that Validation
can accumulate failures "out of the box".
But what about the "new" Try
way? I noticed that Try
has "monadic" methods out of the box also, like map
, flatMap
etc... what was really missing with Either type without help of Projection
.
Thus, I'd imagine each field validation method returning a Try[FieldType]
and more precisely, in case of any failure, a Try[SpecificFieldExceptionType]
; this nested one containing a String
message field and a rootCause field that could be accumulated throughout the build
method.
Using Scala 2.10, could or should Try
practice replace scalaz validation library for simple validation like builder pattern involves?
**EDIT ****
By reading Try
source code, it sounds that Try
can't accumulate several exceptions and thus is oriented fail-fast.
Even Try.flatMap
returns the potentential previous failure and so doesn't have the notion of accumulation:
def flatMap[U](f: T => Try[U]): Try[U] = this.asInstanceOf[Try[U]]
On the contrary of ValidationNEL
that handles accumulation feature.
Any confirmation?
There are tradeoffs:
scalaz.Validation
is able to accumulate errors of type E
given a Semigroup[E]
instance. It's intended for use as an Applicative
, like:
(fragileFoo |@| fragileBar) { case (foo, bar) => doSomething(foo, bar) }
It does have map
and flatMap
methods, biased towards the Success
side, so you can use it conveniently in a for
-comprehension. However, there is no Monad
instance defined for it, so it can't be used in any higher-order stuff (for example, you can't use it with monad transformers). This shortcoming doesn't seem like it would be a problem for you, though.
scalaz.\/
, which you didn't mention, does form a Monad
(again, biased toward the Right
side). But when used as an Applicative
, it doesn't accumulate failures as Validation
does.
util.Try
is similar to scalaz.\/
, specialized to Throwable
. Although it again lacks accumulation of errors, it does have the notion of error recovery. However, for your "builder pattern" use case, it seems like this might not be terribly useful.
Finally, util.Either
isn't worth considering, compared to the other three options: because it's not biased toward one side or the other, you have to explicitly and consistently ask for the left
or right
projection every time you want to do something monadic.
My best guess is that for your situation, scalaz.Validation
is the most appropriate choice.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With