How to functionally compose Scala's Either - scala

If I have one or more Either values how can I compose them in a functional way so that I can log an error if there is a left value but continue in the function if there is a right value. For example
def composeEither(ethr: Either[Error, String]): Either[Error, String] = {
ethr match { case Left(err) => log.error(err.getMessage) }
//this obviously will not work but something like map that is right biased
ethr map { e => e } //Just for the sake of example - there might be a different either calculated within the map
}
Let me know if there is anything else I can add to make my question more clear.

Something like this, maybe:
ether
.right
.flatMap(anotherEither(_).right)
.flatMap(yetAnother(_).right)
.left
.map { err => logError(_.getMessage); err }

Related

How to graciously combine results from two Either's

I have a function in which I need to combine results from two Either objects.
I need the Right side of "request" if "handlingResult" is a Right, and it is a given fact that if "handlingResult" is a Right, "request" is also a Right.
If "handlingResult" is Left, I need its value to build a response.
Right now this is the implementation (both FailingResponse and SuccessfulResponse extend ValuationResponse):
def getResponse(handlingResult : Either[FailureReason, List[StockValuation]]
,request : Either[Error, ValuationRequest]
): ValuationResponse = {
handlingResult.fold(
failureReason =>
FailingResponse(failureReason.message
,failureReason.statusCode),
listOfValuations =>
SuccessfulResponse(listOfValuations
,request.right.get.symbol
,request.right.get.function
,StatusCodes.SUCCESS))
}
But I suspect that accessing an either directly is not a good practice, such as in
request.right.get.symbol
What would be a good way to achieve the same behavior but doing it in a recommendable way?
Either is right-biased in Scala 2.12 and up, so you can use a for-comprehension
def getResponse(handlingResult : Either[FailureReason, List[StockValuation]]
,request : Either[Error, ValuationRequest]
): ValuationResponse = {
val result = for {
result <- handlingResult
req <- request
} yield {
SuccessfulResponse(result, req.symbol, req.function, SUCCESS)
}
result match {
case Right(resp) => resp
case Left(FailureReason(msg, code)) => FailingResponse(msg, code)
case Left(Error) => FailingResponse("failed for unknown reasons", SOME_NEW_CODE)
}
}
Note that although you don't expect the last case statement to ever match, it should be there for completeness, and a new code, SOME_NEW_CODE can be made to indicate that something unexpected occurred.

Return a User if it exists, otherwise inserting if email address Option is present

If I have an email, I want to either get the user by email if it exists. If it doesn't exist, I want to insert and return the User.
val userOptFut: Future[Option[User] = emailOpt.map { email =>
userDao.getByEmail(email).map { maybeUserFut =>
maybeUserFut match {
case Some(u) => Future.successful(Some(u))
case None =>
userDao.insert(User(....)) // Future[User]
}
}
}.getOrElse(Future.successful(None))
Where userDao.getByEmail(..) returns Future[Option[User]]
I am not sure what is wrong, but for some reason it says I am return a Object and not a User.
expression of type Future[Object] does not conform to expected type
Future[Option[User]]
What is wrong with the above?
It's really difficult with nesting like that to match the types up correctly everywhere. What the compiler ends up doing is inferring the most specific type it can, which is Object, and that doesn't match your declared types.
It really helps to break down your functions into smaller pieces, with fewer levels of nesting, so the types are much more difficult to mess up. I would do it something like the following:
// This is very close to Future.sequence, but Option isn't a subclass
// of TraversableOnce. There's probably an existing function to do
// this in a library like cats or scalaz.
def toFutureOption[A](in: Option[Future[A]]): Future[Option[A]] = in match {
case Some(fut) => fut map {Some(_)}
case None => Future.successful(None)
}
def getOrInsert(email: String): Future[User] =
userDao.getByEmail(email) transformWith {
case Success(Some(user)) => Future.successful(user)
case Success(None) | Failure(_) => userDao.insert(User(email))
}
val userOptFut: Future[Option[User]] =
toFutureOption(emailOpt map getOrInsert)
Your problem is that the two branches of your match statement don't return the same type:
case Some(u) => u // User
case None => userDao.insert(User(....)) // Future[User]
Depending on what you are trying to achieve, you could do something like this:
case Some(u) => Future.successful(Some(u))
The .getOrElse at the end may not be suitable for your type either.

Unwrapping Optional Play Route Parameters In Comprehensions

I have the following pattern:
Some play route with some optional parameters defined
GET /my/route controllers.something.Class.method(maybeA: Optional[Int], maybeB: Optional[Int])
In the method, I'd like to be able to use those parameters. I feel like I don't understand the proper pattern to use. What I'd like to do is something like:
blah match {
case Some(someCase) => // do something
case _ => for {
a <- maybeA
b <- maybeB
} yield {
somethingThatReturnsAFuture(a, b)
}
}
The problem is that the for comprehension returns an Option[Future[Int]], but I need it to return Future[Int]. I'd like to be able to just throw a get on the end of the comprehension, but that smells funny (and I don't actually think it's possible to just throw get at the end of the comprehension).
Any suggestions?
If something is Option then the result of the direct processing of this will be Option as well. The only way to get rid of Option is to define the None case.
val resultOpt: Option[Future[Int]] = blah match { ...
val result: Future[Int] = resultOpt match {
case Some(f) => f
case None => Future.successful(0)
}
Or just use getOrElse. The same code, different style:
val resultOpt: Option[Future[Int]] = blah match { ...
val result: Future[Int] = resultOpt.getOrElse(Future.successful(0))
A little bit more about this:
http://alvinalexander.com/scala/how-to-use-multiple-options-for-loop-comprehension

Cleanest way in Scala to avoid nested ifs when transforming collections and checking for error conditions in each step

I have some code for validating ip addresses that looks like the following:
sealed abstract class Result
case object Valid extends Result
case class Malformatted(val invalid: Iterable[IpConfig]) extends Result
case class Duplicates(val dups: Iterable[Inet4Address]) extends Result
case class Unavailable(val taken: Iterable[Inet4Address]) extends Result
def result(ipConfigs: Iterable[IpConfig]): Result = {
val invalidIpConfigs: Iterable[IpConfig] =
ipConfigs.filterNot(ipConfig => {
(isValidIpv4(ipConfig.address)
&& isValidIpv4(ipConfig.gateway))
})
if (!invalidIpConfigs.isEmpty) {
Malformatted(invalidIpConfigs)
} else {
val ipv4it: Iterable[Inet4Address] = ipConfigs.map { ipConfig =>
InetAddress.getByName(ipConfig.address).asInstanceOf[Inet4Address]
}
val dups = ipv4it.groupBy(identity).filter(_._2.size != 1).keys
if (!dups.isEmpty) {
Duplicates(dups)
} else {
val ipAvailability: Map[Inet4Address, Boolean] =
ipv4it.map(ip => (ip, isIpAvailable(ip)))
val taken: Iterable[Inet4Address] = ipAvailability.filter(!_._2).keys
if (!taken.isEmpty) {
Unavailable(taken)
} else {
Valid
}
}
}
}
I don't like the nested ifs because it makes the code less readable. Is there a nice way to linearize this code? In java, I might use return statements, but this is discouraged in scala.
I personally advocate using a match everywhere you can, as it in my opinion usually makes code very readable
def result(ipConfigs: Iterable[IpConfig]): Result =
ipConfigs.filterNot(ipc => isValidIpv4(ipc.address) && isValidIpv4(ipc.gateway)) match {
case Nil =>
val ipv4it = ipConfigs.map { ipc =>
InetAddress.getByName(ipc.address).asInstanceOf[Inet4Address]
}
ipv4it.groupBy(identity).filter(_._2.size != 1).keys match {
case Nil =>
val taken = ipv4it.map(ip => (ip, isIpAvailable(ip))).filter(!_._2).keys
if (taken.nonEmpty) Unavailable(taken) else Valid
case dups => Duplicates(dups)
}
case invalid => Malformatted(invalid)
}
Note that I've chosen to match on the else part first, since you generally go from specific to generic in matches, since Nil is a subclass of Iterable I put that as the first case, eliminating the need for an i if i.nonEmpty in the other case, since it would be a given if it didn't match Nil
Also a thing to note here, all your vals don't need the type explicitly defined, it significantly declutters the code if you write something like
val ipAvailability: Map[Inet4Address, Boolean] =
ipv4it.map(ip => (ip, isIpAvailable(ip)))
as simply
val ipAvailability = ipv4it.map(ip => (ip, isIpAvailable(ip)))
I've also taken the liberty of removing many one-off variables I didn't find remotely necessary, as all they did was add more lines to the code
A thing to note here about using match over nested ifs, is that is that it's easier to add a new case than it is to add a new else if 99% of the time, thereby making it more modular, and modularity is always a good thing.
Alternatively, as suggested by Nathaniel Ford, you can break it up into several smaller methods, in which case the above code would look like so:
def result(ipConfigs: Iterable[IpConfig]): Result =
ipConfigs.filterNot(ipc => isValidIpv4(ipc.address) && isValidIpv4(ipc.gateway)) match {
case Nil => wellFormatted(ipConfigs)
case i => Malformatted(i)
}
def wellFormatted(ipConfigs: Iterable[IpConfig]): Result = {
val ipv4it = ipConfigs.map(ipc => InetAddress.getByName(ipc.address).asInstanceOf[Inet4Address])
ipv4it.groupBy(identity).filter(_._2.size != 1).keys match {
case Nil => noDuplicates(ipv4it)
case dups => Duplicates(dups)
}
}
def noDuplicates(ipv4it: Iterable[IpConfig]): Result =
ipv4it.map(ip => (ip, isIpAvailable(ip))).filter(!_._2).keys match {
case Nil => Valid
case taken => Unavailable(taken)
}
This has the benefit of splitting it up into smaller more manageable chunks, while keeping to the FP ideal of having functions that only do one thing, but do that one thing well, rather than having god-methods that do everything.
Which style you prefer, of course is up to you.
This has some time now but I will add my 2 cents. The proper way to handle this is with Either. You can create a method like:
def checkErrors[T](errorList: Iterable[T], onError: Result) : Either[Result, Unit] = if(errorList.isEmpty) Right() else Left(onError)
so you can use for comprehension syntax
val invalidIpConfigs = getFormatErrors(ipConfigs)
val result = for {
_ <- checkErrors(invalidIpConfigs, Malformatted(invalidIpConfigs))
dups = getDuplicates(ipConfigs)
_ <- checkErrors(dups, Duplicates(dups))
taken = getAvailability(ipConfigs)
_ <- checkErrors(taken, Unavailable(taken))
} yield Valid
If you don't want to return an Either use
result.fold(l => l, r => r)
In case of the check methods uses Futures (could be the case for getAvailability, for example), you can use cats library to be able of use it in a clean way: https://typelevel.org/cats/datatypes/eithert.html
I think it's pretty readable and I wouldn't try to improve it from there, except that !isEmpty equals to nonEmpty.

Chaining validation in Scala

I have a Scala case class containing command-line configuration information:
case class Config(emailAddress: Option[String],
firstName: Option[String]
lastName: Option[String]
password: Option[String])
I am writing a validation function that checks that each of the values is a Some:
def validateConfig(config: Config): Try[Config] = {
if (config.emailAddress.isEmpty) {
Failure(new IllegalArgumentException("Email Address")
} else if (config.firstName.isEmpty) {
Failure(new IllegalArgumentException("First Name")
} else if (config.lastName.isEmpty) {
Failure(new IllegalArgumentException("Last Name")
} else if (config.password.isEmpty) {
Failure(new IllegalArgumentException("Password")
} else {
Success(config)
}
}
but if I understand monads from Haskell, it seems that I should be able to chain the validations together (pseudo syntax):
def validateConfig(config: Config): Try[Config] = {
config.emailAddress.map(Success(config)).
getOrElse(Failure(new IllegalArgumentException("Email Address")) >>
config.firstName.map(Success(config)).
getOrElse(Failure(new IllegalArgumentException("First Name")) >>
config.lastName.map(Success(config)).
getOrElse(Failure(new IllegalArgumentException("Last Name")) >>
config.password.map(Success(config)).
getOrElse(Failure(new IllegalArgumentException("Password"))
}
If any of the config.XXX expressions returns Failure, the whole thing (validateConfig) should fail, otherwise Success(config) should be returned.
Is there some way to do this with Try, or maybe some other class?
It's pretty straightforward to convert each Option to an instance of the right projection of Either:
def validateConfig(config: Config): Either[String, Config] = for {
_ <- config.emailAddress.toRight("Email Address").right
_ <- config.firstName.toRight("First Name").right
_ <- config.lastName.toRight("Last Name").right
_ <- config.password.toRight("Password").right
} yield config
Either isn't a monad in the standard library's terms, but its right projection is, and will provide the behavior you want in the case of failure.
If you'd prefer to end up with a Try, you could just convert the resulting Either:
import scala.util._
val validate: Config => Try[Config] = (validateConfig _) andThen (
_.fold(msg => Failure(new IllegalArgumentException(msg)), Success(_))
)
I wish that the standard library provided a nicer way to make this conversion, but it doesn't.
It's a case class, so why aren't you doing this with pattern matching?
def validateConfig(config: Config): Try[Config] = config match {
case Config(None, _, _, _) => Failure(new IllegalArgumentException("Email Address")
case Config(_, None, _, _) => Failure(new IllegalArgumentException("First Name")
case Config(_, _, None, _) => Failure(new IllegalArgumentException("Last Name")
case Config(_, _, _, None) => Failure(new IllegalArgumentException("Password")
case _ => Success(config)
}
In your simple example, my priority would be to forget monads and chaining, just get rid of that nasty if...else smell.
However, while a case class works perfectly well for a short list, for a large number of configuration options, this becomes tedious and the risk of error increases. In this case, I would consider something like this:
Add a method that returns a key->value map of the configuration options, using the option names as the keys.
Have the Validate method check if any value in the map is None
If no such value, return success.
If at least one value matches, return that value name with the error.
So assuming that somewhere is defined
type OptionMap = scala.collection.immutable.Map[String, Option[Any]]
and the Config class has a method like this:
def optionMap: OptionMap = ...
then I would write Config.validate like this:
def validate: Either[List[String], OptionMap] = {
val badOptions = optionMap collect { case (s, None) => s }
if (badOptions.size > 0)
Left(badOptions)
else
Right(optionMap)
}
So now Config.validate returns either a Left containing the name of all the bad options or a Right containing the full map of options and their values. Frankly, it probably doesn't matter what you put in the Right.
Now, anything that wants to validate a Config just calls Config.validate and examines the result. If it's a Left, it can throw an IllegalArgumentException containing one or more of the names of bad options. If it's a Right, it can do whatever it wanted to do, knowing the Config is valid.
So we could rewrite your validateConfig function as
def validateConfig(config: Config): Try[Config] = config.validate match {
case Left(l) => Failure(new IllegalArgumentException(l.toString))
case _ => Success(config)
}
Can you see how much more functional and OO this is getting?
No imperative chain of if...else
The Config object validates itself
The consequences of a Config object being invalid are left to the larger program.
I think a real example would be more complex yet, though. You are validating options by saying "Does it contain Option[String] or None?" but not checking the validity of the string itself. Really, I think your Config class should contain a map of options where the name maps to the value and to an anonymous function that validates the string. I could describe how to extend the above logic to work with that model, but I think I'll leave that as an exercise for you. I will give you a hint: you might want to return not just the list of failed options, but also the reason for failure in each case.
Oh, by the way... I hope none of the above implies that I think you should actually store the options and their values as an optionMap inside the object. I think it's useful to be able to retrieve them like that, but I wouldn't ever encourage such exposure of the actual internal representation ;)
Here's a solution that I came up with after some searching and scaladocs reading:
def validateConfig(config: Config): Try[Config] = {
for {
_ <- Try(config.emailAddress.
getOrElse(throw new IllegalArgumentException("Email address missing")))
_ <- Try(config.firstName.
getOrElse(throw new IllegalArgumentException("First name missing")))
_ <- Try(config.lastName.
getOrElse(throw new IllegalArgumentException("Last name missing")))
_ <- Try(config.password.
getOrElse(throw new IllegalArgumentException("Password missing")))
} yield config
}
Similar to Travis Brown's answer.