Are there any conversions from Either to Try and vice versa in the Scala standard library ? Maybe I am missing something but I did not find them.
To the best of my knowledge this does not exist in the standard library. Although an Either is typically used with the Left being a failure and the Right being a success, it was really designed to support the concept of two possible return types with one not necessarily being a failure case. I'm guessing these conversions that one would expect to exist do not exist because Either was not really designed to be a Success/Fail monad like Try is. Having said that it would be pretty easy to enrich Either yourself and add these conversions. That could look something like this:
object MyExtensions {
implicit class RichEither[L <: Throwable,R](e:Either[L,R]){
def toTry:Try[R] = e.fold(Failure(_), Success(_))
}
implicit class RichTry[T](t:Try[T]){
def toEither:Either[Throwable,T] = t.transform(s => Success(Right(s)), f => Success(Left(f))).get
}
}
object ExtensionsExample extends App{
import MyExtensions._
val t:Try[String] = Success("foo")
println(t.toEither)
val t2:Try[String] = Failure(new RuntimeException("bar"))
println(t2.toEither)
val e:Either[Throwable,String] = Right("foo")
println(e.toTry)
val e2:Either[Throwable,String] = Left(new RuntimeException("bar"))
println(e2.toTry)
}
In Scala 2.12.x Try has a toEither method: http://www.scala-lang.org/api/2.12.x/scala/util/Try.html#toEither:scala.util.Either[Throwable,T]
import scala.util.{ Either, Failure, Left, Right, Success, Try }
implicit def eitherToTry[A <: Exception, B](either: Either[A, B]): Try[B] = {
either match {
case Right(obj) => Success(obj)
case Left(err) => Failure(err)
}
}
implicit def tryToEither[A](obj: Try[A]): Either[Throwable, A] = {
obj match {
case Success(something) => Right(something)
case Failure(err) => Left(err)
}
}
The answer depends on how to convert the Failure to Left (and vice versa). If you don't need to use the details of the exception, then Try can be converted to Either by going the intermediate route of an Option:
val tried = Try(1 / 0)
val either = tried.toOption.toRight("arithmetic error")
The conversion the other way requires you to construct some Throwable. It could be done like this:
either.fold(left => Failure(new Exception(left)), right => Success(right))
Related
I have handled exception as follows:
def calculate(input: Option[Double]): Try[String] =
Try {
input match {
case (Some(value)) => value.toString
case (None) => throw new IllegalArgumentException("No value found")
}
}
And in client code:
val result = calculate(....)
result match {
case Success(i) => println(i)
case Failure(s) => throw s // or log(s) to log the issue and continue
}
Is it good enough practice or much better can be done for clean and elegant code base?
Try usually used to cover parts which might throw an error, like in cases if you are using some Java libs, which can throw an exception. But, if you would like to return possible error and force client to handle it, Either[A, B] is much better option, at least because you can specify more precise error type for Left[A] and safely to pattern match over your's A type, instead of do possibly incorrect pattern matching against some Throwable, like you would do for Failure(t).
So, in your case possible solution would look like:
sealed trait CalculationError
case class Error1(cause: String) extends CalculationError
def calculate(input: Option[Double]): Either[CalculationError, String] =
input match {
case (Some(value)) => Right(value.toString)
case (None) => Left(Error1("No value found"))
}
}
val result = calculate(....)
result match {
case Right(i) => println(i)
case Left(Error1(s)) => println(s)
}
This is safer approach, because you can later add another type of error , say case class Error2(cause: String) extends CalculationError and on client pattern matching code part, compile will show a warn message that you missed handling of new error: Match is not exhaustive. In case of Failure(t) compile won't be able suggest such warning, so it's easier to make mistake on error handling side.
Hope this helps!
I had written a Reads converter in play-json for Option[Option[A]] that had the following behavior:
//given this case class
case class MyModel(field: Option[Option[String]])
//this JSON -- maps to --> this MyModel:
//"{ \"field\": \"value\" }" --> MyModel(field = Some(Some("value")))
//"{ \"field\": null, ... }" --> MyModel(field = Some(None))
//"{ }" --> MyModel(field = None)
So, providing the value mapped to Some[Some[A]], providing null mapped to Some[None] (i.e. Some[Option.empty[A]]), and not providing the value mapped to just None (i.e. Option.empty[Option[A]]). Here's the play-json converter:
def readOptOpt[A](implicit r: Reads[A]): Reads[Option[Option[A]]] = {
Reads[Option[Option[A]]] { json =>
path.applyTillLast(json).fold(
identity,
_.fold(_ => JsSuccess(None), {
case JsNull => JsSuccess(Some(None))
case js => r.reads(js).repath(path).map(a => Some(Some(a)))
})
)
}
}
Now I am converting my play-json code to Circe, but I can't figure out how to write a Decoder[Option[Option[A]] that has the same behavior. That is, I need
def optOptDecoder[A](implicit d: Decoder[A]): Decoder[Option[Option[A]] = ??? //help!
Any ideas on how I can make this work? Thanks
I figured this out:
There were two problems:
1) How to deal with the case where the field was completely missing from the JSON. Turns out you have to use Decoder.reattempt in your custom decoder, following Circe's decodeOption code, which works.
2) How to have the compiler recognize cases of Option[Option[A]] when your decoder code is sitting in a helper object (or wherever). Turns out if you're using semi-auto derivation, you can create an implicit in the companion object and that will override the defaults:
//companion object
object MyModel {
implicit def myModelOptOptDecoder[A](implicit d: Decoder[A]): Decoder[Option[Option[A]]] =
MyHelperObject.optOptDecoder
implicit val myModelDecoder: Decoder[MyModel] = deriveDecoder
}
Anyway, I don't think this will be much help to anybody in the future, so unless I get any upvotes in the next few hours I think I'll just delete this.
Edit2: Okay it was answered so I won't delete it. Stay strong, esoteric circe question, stay strong...
An Option[Option[A]] is a bit odd. I understand and mostly agree with the reasoning, but I think it's weird enough that it may warrant just replacing it with your own class (and writing a decoder for that). Something like:
sealed trait OptionalNull[+A] {
def toOption: Option[Option[A]]
}
object NotPresent extends OptionalNull[Nothing] {
override def toOption = None
}
object PresentButNull extends OptionalNull[Nothing] {
override def toOption = Some(None)
}
case class PresentNotNull[A](value: A) extends OptionalNull[A] {
override def toOption = Some(Some(value))
}
This has the additional benefit of not having to worry about implicit precedence and stuff like that. Might simplify your decoder.
Here is another solution I found (This is not my gist):
sealed trait UpdateOrDelete[+A]
case object Delete extends UpdateOrDelete[Nothing]
final case class UpdateOptionalFieldWith[A](value: A) extends UpdateOrDelete[A]
object UpdateOrDelete {
implicit def optionalDecoder[A](implicit decodeA: Decoder[A]): Decoder[UpdateOptionalField[A]] =
Decoder.withReattempt {
// We're trying to decode a field but it's missing.
case c: FailedCursor if !c.incorrectFocus => Right(None)
case c =>
Decoder.decodeOption[A].tryDecode(c).map {
case Some(a) => Some(UpdateOptionalFieldWith(a))
case None => Some(Delete)
}
}
// Random UUID to _definitely_ avoid collisions
private[this] val marker: String = s"$$marker-${UUID.randomUUID()}-marker$$"
private[this] val markerJson: Json = Json.fromString(marker)
implicit def optionalEncoder[A](implicit encodeA: Encoder[A]): Encoder[UpdateOptionalField[A]] =
Encoder.instance {
case Some(Delete) => Json.Null
case Some(UpdateOptionalFieldWith(a)) => encodeA(a)
case None => markerJson
}
def filterMarkers[A](encoder: Encoder.AsObject[A]): Encoder.AsObject[A] =
encoder.mapJsonObject { obj =>
obj.filter {
case (_, value) => value =!= markerJson
}
}
}
I have an app that manages Items. When the client queries an item by some info, the app first tries to find an existing item in the db with the info. If there isn't one, the app would
Check if info is valid. This is an expensive operation (much more so than a db lookup), so the app only performs this when there isn't an existing item in the db.
If info is valid, insert a new Item into the db with info.
There are two more classes, ItemDao and ItemService:
object ItemDao {
def findByInfo(info: Info): Future[Option[Item]] = ...
// This DOES NOT validate info; it assumes info is valid
def insertIfNotExists(info: Info): Future[Item] = ...
}
object ItemService {
// Very expensive
def isValidInfo(info: Info): Future[Boolean] = ...
// Ugly
def findByInfo(info: Info): Future[Option[Item]] = {
ItemDao.findByInfo(info) flatMap { maybeItem =>
if (maybeItem.isDefined)
Future.successful(maybeItem)
else
isValidInfo(info) flatMap {
if (_) ItemDao.insertIfNotExists(info) map (Some(_))
else Future.successful(None)
}
}
}
}
The ItemService.findByInfo(info: Info) method is pretty ugly. I've been trying to clean it up for a while, but it's difficult since there are three types involved (Future[Boolean], Future[Item], and Future[Option[Item]]). I've tried to use scalaz's OptionT to clean it up but the non-optional Futures make it not very easy either.
Any ideas on a more elegant implementation?
To expand on my comment.
Since you've already indicated a willingness to go down the route of monad transformers, this should do what you want. There is unfortunately quite a bit of line noise due to Scala's less than stellar typechecking here, but hopefully you find it elegant enough.
import scalaz._
import Scalaz._
object ItemDao {
def findByInfo(info: Info): Future[Option[Item]] = ???
// This DOES NOT validate info; it assumes info is valid
def insertIfNotExists(info: Info): Future[Item] = ???
}
object ItemService {
// Very expensive
def isValidInfo(info: Info): Future[Boolean] = ???
def findByInfo(info: Info): Future[Option[Item]] = {
lazy val nullFuture = OptionT(Future.successful(none[Item]))
lazy val insert = ItemDao.insertIfNotExists(info).liftM[OptionT]
lazy val validation =
isValidInfo(info)
.liftM[OptionT]
.ifM(insert, nullFuture)
val maybeItem = OptionT(ItemDao.findByInfo(info))
val result = maybeItem <+> validation
result.run
}
}
Two comments about the code:
We are using the OptionT monad transformer here to capture the Future[Option[_]] stuff and anything that just lives inside Future[_] we're liftMing up to our OptionT[Future, _] monad.
<+> is an operation provided by MonadPlus. In a nutshell, as the name suggests, MonadPlus captures the intuition that often times monads have an intuitive way of being combined (e.g. List(1, 2, 3) <+> List(4, 5, 6) = List(1, 2, 3, 4, 5, 6)). Here we're using it to short-circuit when findByInfo returns Some(item) rather than the usual behavior to short-circuit on None (this is roughly analogous to List(item) <+> List() = List(item)).
Other small note, if you actually wanted to go down the monad transformers route, often times you end up building everything in your monad transformer (e.g. ItemDao.findByInfo would return an OptionT[Future, Item]) so that you don't have extraneous OptionT.apply calls and then .run everything at the end.
You don't need scalaz for this. Just break your flatMap into two steps:
first, find and validate, then insert if necessary. Something like this:
ItemDao.findByInfo(info).flatMap {
case None => isValidInfo(info).map(None -> _)
case x => Future.successful(x -> true)
}.flatMap {
case (_, true) => ItemDao.insertIfNotExists(info).map(Some(_))
case (x, _) => Future.successful(x)
}
Doesn't look too bad, does it? If you don't mind running validation in parallel with retrieval (marginally more expensive resource-vise, but likely faster on average), you could further simplify it like this:
ItemDao
.findByInfo(info)
.zip(isValidInfo(info))
.flatMap {
case (None, true) => ItemDao.insertIfNotExists(info).map(Some(_))
case (x, _) => x
}
Also, what does insertIfNotExists return if the item does exist? If it returned the existing item, things could be even simpler:
isValidInfo(info)
.filter(identity)
.flatMap { _ => ItemDao.insertIfNotExists(info) }
.map { item => Some(item) }
.recover { case _: NoSuchElementException => None }
If you are comfortable with path-dependent type and higher-kinded type, something like the following can be an elegant solution:
type Const[A] = A
sealed trait Request {
type F[_]
type A
type FA = F[A]
def query(client: Client): Future[FA]
}
case class FindByInfo(info: Info) extends Request {
type F[x] = Option[x]
type A = Item
def query(client: Client): Future[Option[Item]] = ???
}
case class CheckIfValidInfo(info: Info) extends Request {
type F[x] = Const[x]
type A = Boolean
def query(client: Client): Future[Boolean] = ???
}
class DB {
private val dbClient: Client = ???
def exec(request: Request): request.FA = request.query(dbClient)
}
What this does is basically to abstract over both the wrapper type (eg. Option[_]) as well as inner type. For types without a wrapper type, we use Const[_] type which is basically an identity type.
In scala, many problems alike this can be solved elegantly using Algebraic Data Type and its advanced type system (i.e path-dependent type & higher-kinded type). Note that now we have single point of entry exec(request: Request) for executing db requests instead of something like DAO.
Is there a "better" way to do this?
import java.awt.event.MouseEvent
trait MouseListener extends java.awt.event.MouseListener{
def mouseClicked(e:MouseEvent){}
def mousePressed(e:MouseEvent){}
def mouseReleased(e:MouseEvent){}
def mouseEntered(e:MouseEvent){}
def mouseExited(e:MouseEvent){}
}
I made this trait so I could do this without overriding the methods I am not using.
This works fine I am just wondering if there is an alternative method?
new ActionListener{
override def mouseClicked(e:MouseEvent){
//Blah Blah
}
}
This is built-in already: MouseAdapter. There are similar classes for other Swing listener interfaces with more than one method.
By "better" way, I suppose you mean "Scala way."
On a scala.swing.UIElement:
listenTo(mouse.clicks, mouse.moves, mouse.wheel, keys)
reactions += {
case e: MousePressed => startDrag(e)
case e: MouseDragged => doDrag(e)
case e: MouseReleased => endDrag(e)
case e: MouseWheelMoved => wheeling(e)
case _ => null // println ("Unreacted event")
}
Very often i end up with lots of nested .map and .getOrElse when validating several consecutives conditions
for example:
def save() = CORSAction { request =>
request.body.asJson.map { json =>
json.asOpt[Feature].map { feature =>
MaxEntitiyValidator.checkMaxEntitiesFeature(feature).map { rs =>
feature.save.map { feature =>
Ok(toJson(feature.update).toString)
}.getOrElse {
BadRequest(toJson(
Error(status = BAD_REQUEST, message = "Error creating feature entity")
))
}
}.getOrElse {
BadRequest(toJson(
Error(status = BAD_REQUEST, message = "You have already reached the limit of feature.")
))
}
}.getOrElse {
BadRequest(toJson(
Error(status = BAD_REQUEST, message = "Invalid feature entity")
))
}
}.getOrElse {
BadRequest(toJson(
Error(status = BAD_REQUEST, message = "Expecting JSON data")
))
}
}
You get the idea
I just wanted to know if there's some idiomatic way to keep it more clear
If you hadn't had to return a different message for the None case this would be an ideal use-case for for comprehension. In your case , you probably want to use the Validation monad, as the one you can find in Scalaz. Example ( http://scalaz.github.com/scalaz/scalaz-2.9.0-1-6.0/doc.sxr/scalaz/Validation.scala.html ).
In functional programming, you should not throw exceptions but let functions which can fail return an Either[A,B], where by convention A is the type of result in case of failure and B is the type of result in case of success. You can then match against Left(a) or Right(b) to handle, reespectively, the two cases.
You can think of the Validation monad as an extended Either[A,B] where applying subsequent functions to a Validation will either yield a result, or the first failure in the execution chain.
sealed trait Validation[+E, +A] {
import Scalaz._
def map[B](f: A => B): Validation[E, B] = this match {
case Success(a) => Success(f(a))
case Failure(e) => Failure(e)
}
def foreach[U](f: A => U): Unit = this match {
case Success(a) => f(a)
case Failure(e) =>
}
def flatMap[EE >: E, B](f: A => Validation[EE, B]): Validation[EE, B] = this match {
case Success(a) => f(a)
case Failure(e) => Failure(e)
}
def either : Either[E, A] = this match {
case Success(a) => Right(a)
case Failure(e) => Left(e)
}
def isSuccess : Boolean = this match {
case Success(_) => true
case Failure(_) => false
}
def isFailure : Boolean = !isSuccess
def toOption : Option[A] = this match {
case Success(a) => Some(a)
case Failure(_) => None
}
}
final case class Success[E, A](a: A) extends Validation[E, A]
final case class Failure[E, A](e: E) extends Validation[E, A]
Your code now can be refactored by using the Validation monad into three validation layers. You should basically replace your map with a validation like the following:
def jsonValidation(request:Request):Validation[BadRequest,String] = request.asJson match {
case None => Failure(BadRequest(toJson(
Error(status = BAD_REQUEST, message = "Expecting JSON data")
)
case Some(data) => Success(data)
}
def featureValidation(validatedJson:Validation[BadRequest,String]): Validation[BadRequest,Feature] = {
validatedJson.flatMap {
json=> json.asOpt[Feature] match {
case Some(feature)=> Success(feature)
case None => Failure( BadRequest(toJson(
Error(status = BAD_REQUEST, message = "Invalid feature entity")
)))
}
}
}
And then you chain them like the following featureValidation(jsonValidation(request))
This is a classic example of where using a monad can clean up your code. For example you could use Lift's Box, which is not tied to Lift in any way. Then your code would look something like this:
requestBox.flatMap(asJSON).flatMap(asFeature).flatMap(doSomethingWithFeature)
where asJson is a Function from a request to a Box[JSON] and asFeature is a function from a Feature to some other Box. The box can contain either a value, in which case flatMap calls the function with that value, or it can be an instance of Failure and in that case flatMap does not call the function passed to it.
If you had posted some example code that compiles, I could have posted an answer that compiles.
I tried this to see if pattern matching offered someway to adapt the submitted code sample (in style, if not literally) to something more coherent.
object MyClass {
case class Result(val datum: String)
case class Ok(val _datum: String) extends Result(_datum)
case class BadRequest(_datum: String) extends Result(_datum)
case class A {}
case class B(val a: Option[A])
case class C(val b: Option[B])
case class D(val c: Option[C])
def matcher(op: Option[D]) = {
(op,
op.getOrElse(D(None)).c,
op.getOrElse(D(None)).c.getOrElse(C(None)).b,
op.getOrElse(D(None)).c.getOrElse(C(None)).b.getOrElse(B(None)).a
) match {
case (Some(d), Some(c), Some(b), Some(a)) => Ok("Woo Hoo!")
case (Some(d), Some(c), Some(b), None) => BadRequest("Missing A")
case (Some(d), Some(c), None, None) => BadRequest("Missing B")
case (Some(d), None, None, None) => BadRequest("Missing C")
case (None, None, None, None) => BadRequest("Missing D")
case _ => BadRequest("Egads")
}
}
}
Clearly there are ways to write this more optimally; this is left as an exercise for the reader.
I agree with Edmondo suggestion of using for comprehension but not with the part about using a validation library (At least not anymore given the new features added to scala standard lib since 2012). From my experience with scala, dev that struggle to come up with nice statement with the standard lib will also end up doing the same of even worst when using libs like cats or scalaz. Maybe not at the same place, but ideally we would solve the issue rather than just moving it.
Here is your code rewritten with for comprehension and either that is part of scala standard lib :
def save() = CORSAction { request =>
// Helper to generate the error
def badRequest(message: String) = Error(status = BAD_REQUEST, message)
//Actual validation
val updateEither = for {
json <- request.body.asJson.toRight(badRequest("Expecting JSON data"))
feature <- json.asOpt[Feature].toRight(badRequest("Invalid feature entity"))
rs <- MaxEntitiyValidator
.checkMaxEntitiesFeature(feature)
.toRight(badRequest("You have already reached the limit"))
} yield toJson(feature.update).toString
// Turn the either into an OK/BadRequest
featureEither match {
case Right(update) => Ok(update)
case Left(error) => BadRequest(toJson(error))
}
}
Explanations
Error handling
I'm not sure how much you know about either but they are pretty similar in behaviour as Validation presented by Edmondo or Try object from the scala library. Main difference between those object regard their capability and behaviour with errors, but beside that they all can be mapped and flat mapped the same way.
You can also see that I use toRight to immediately convert the option into Either instead of doing it at the end. I see that java dev have the reflex to throw exception as far as they physically can, but they mostly do so because the try catch mechanism is unwieldy: in case of success, to get data out of a try block you either need to return them or put them in a variable initialized to null out of the block. But this is not the case is scala: you can map a try or an either, so in general, you get a more legible code if you turn results into error representation as soon as have identified it as they are identified as incorrect.
For comprehension
I also know that dev discovering scala are often quite puzzled by for comprehension. This is quite understandable as in most other language, for is only used for iteration over collections while is scala, it seem to use usable on a lot of unrelated types. In scala for is actually more nicer way to call the function flatMap. The compiler may decide to optimize it with map or foreach but it remain correct assume that you will get a flatMap behavior when you use for.
Calling flatMap on a collection will behave like the for each would in other language, so scala for may be used like a standard for when dealing with collection. But you can also use it on any other type of object that provide an implementation for flatMap with the correct signature. If your OK/BadRequest also implement the flatMap, you may be able to use in directly in the for comprehension instead of usong an intermediate Either representation.
For the people are not at ease with using for on anything that do not look like a collection, here is is how the function would look like if explicitly using flatMap instead of for :
def save() = CORSAction { request =>
def badRequest(message: String) = Error(status = BAD_REQUEST, message)
val updateEither = request.body.asJson.toRight(badRequest("Expecting JSON data"))
.flatMap { json =>
json
.asOpt[Feature]
.toRight(badRequest("Invalid feature entity"))
}
.flatMap { feature =>
MaxEntitiyValidator
.checkMaxEntitiesFeature(feature)
.map(_ => feature)
.toRight(badRequest("You have already reached the limit"))
}
.map { rs =>
toJson(feature.update).toString
}
featureEither match {
case Right(update) => Ok(update)
case Left(error) => BadRequest(toJson(error))
}
}
Note that in term of parameter scope, for behave live if the function where nested, not chained.
Conclusion
I think that more than not using the right framework or the right language feature, the main issue with the code your provided is how errors are dealt with. In general, you should not write error paths as after thought that you pile up at the end of the method. If you can deal with the error immediately as they occur, that allow you to move to something else. On the contrary, the more you push them back, the more you will have code with inextricable nesting. They are actually a materialization of all the pending error cases that scala expect you to deal with at some point.