How can I (best) convert an Option returned by a method call into a Try (by preference, although an Either or a scalaz \/
or even a Validation might be OK) including specifying a Failure value if appropriate?
For example, I have the following code, which feels kludgy, but does at least do (most of) the job:
import scala.util._
case class ARef(value: String)
case class BRef(value: String)
case class A(ref: ARef, bRef: BRef)
class MismatchException(msg: String) extends RuntimeException(msg)
trait MyTry {
// Given:
val validBRefs: List[BRef]
// Want to go from an Option[A] (obtained, eg., via a function call passing a provided ARef)
// to a Try[BRef], where the b-ref needs to be checked against the above list of BRefs or fail:
def getValidBRefForReferencedA(aRef: ARef): Try[BRef] = {
val abRef = for {
a <- get[A](aRef) // Some function that returns an Option[A]
abRef = a.bRef
_ <- validBRefs.find(_ == abRef)
} yield (abRef)
abRef match {
case Some(bRef) => Success(bRef)
case None => Failure(new MismatchException("No B found matching A's B-ref"))
}
}
}
It feels like there should be a way for the final match to be morphed into a map or flatMap or similar construct and incorporated into the preceeding for comprehension.
Also, I would prefer to be able to specify a different failure message if the call to return an Option[A] from the ARef failed (returned None) compared to the BRef check failing (I only care about knowing one reason for the failure, so a scalaz Validation doesn't feel like the ideal fit).
Is this a suitable place to use a monad transformer? If so, does scalaz provide a suitable one, or can someone give an example of what it would look like?
Short and simple
no need for fancy mapping. In case the option is empty you get an error like:
[Edited to identify different failures]
Tried to simplify
I have worked out an alternative solution, although it still doesn't allow me to specify a different failure message for the case that the Option[A] is None versus the BRef not being valid:
I guess I am expecting it should be possible to have a way to quickly convert the returned Option[A] into a Try (in a suitably idiomatic Scala way - eg. inside a for-comprehension), then continue the processing (obtaining and checking the b-ref) while setting any appropriate Failures along the way.
If you start out with a
Try
from the get go with your for-comp then you can eliminate the match at the end. You can do this by forcing theOption
to aTry
viafold
. Here's what that could look like:With this approach, you can get different exceptions for the two different checks. It's not perfect, but maybe it will work for you.
If you want to use an
Either
, you can useOption.toRight
:Using a
Try
, you can simply write your code in a very procedural way, by throwing appropriate exceptions where needed and wrapping the whole withTry.apply
(which will catch the exception and present them asFailure
instances).You can use an implicit conversion
Scala standard lib uses this type of approach. See http://docs.scala-lang.org/tutorials/FAQ/finding-implicits.html#companion-objects-of-a-type