What is the cleanest way in Scala to convert from Future[Option[Future[Int]]] to Future[Option[Int]]? Is it even possible?
There are two nested Futures that you roll into one, so this calls for a flatMap.
def flatten[A](f: Future[Option[Future[A]]]): Future[Option[A]] =
f.flatMap({
case None => Future.successful(None)
case Some(g) => g.map(Some(_))
})
Or, more concisely:
def flatten[A](f: Future[Option[Future[A]]]): Future[Option[A]] =
f.flatMap(o => Future.sequence(o.toSeq).map(_.headOption))
Thanks to #lmm's answer for the idea on that. Ideally this could be written as f.flatMap(Future.sequence), but unfortunately sequence expects a TraversableOnce, which Option does not extend.
The cleanest way is probably using scalaz:
import scalaz.std.option._
import scalaz.std.scalaFuture._
import scalaz.syntax.traverse._
//assuming implicit execution context in scope
f.flatMap(_.sequence)
You are asking how to code your way out of some paper bag, and you have gotten some good answers about how to do this, however you should be stepping back and trying to just not get into the paper bag you are currently in. See my answer here: Get rid of Scala Future nesting about how to avoid getting into a Future[X[Future[y]] type signature so that you don't have to figure out how to then get out of it.
Related
Given I'm using reflection to go through a list of members (giving me runtime.universe.Symbol), how can I check the generic type without the type arguments? In other words, how do I find the members which are List[] generic type, regardless of what the type argument is?
Currently I'm using this approach which does work, but I'm wondering if there's a better way to do it:
import scala.reflect.runtime.currentMirror
// ...
val listTypeConstructor = typeOf[List[_]].typeConstructor
val myListMembers = currentMirror.reflect(MyObject)
.symbol
.asClass
.typeSignature
.members
.filter(member => member.typeSignature.resultType.typeConstructor == listTypeConstructor)
This results in a list of runtime.universe.Symbol of all the List[] members, including any List[String], List[Int], etc. as expected.
The usage of typeOf[List[_]].typeConstructor seems a bit messy to me though. Is this the best way to do this kind of filtering?
The answer is no. The way I have it in the example above is the standard way.
Given:
def convert[T](list: List[Either[String, T]]): Validated[NonEmptyList[String], NonEmptyList[T]] =
NonEmptyList.fromList(list)
.toRight("list is empty")
.flatMap(...
How do I flat map the NonEmptyList[Either[String, T]] so ultimately I end up with my Validated return value?
Is there anything in the cats library to account for this scenario? Or do I need to do this manually following something like: Best way to turn a Lists of Eithers into an Either of Lists?
I'd write this as follows:
import cats.data.{ NonEmptyList, Validated, ValidatedNel }
import cats.instances.list._, cats.syntax.list._
import cats.syntax.either._
import cats.syntax.option._
import cats.syntax.traverse._
def convert[T](list: List[Either[String, T]]): ValidatedNel[String, NonEmptyList[T]] =
list.traverse(_.toValidatedNel).andThen(_.toNel.toValidNel("list is empty"))
First we flip the whole thing inside out while transforming the Eithers to Validateds (with traverse and toValidatedNel), to get a ValidatedNel[String, List[T]], and then we handle the case where the result is empty (with andThen and toNel).
The andThen is probably one of the pieces you're missing—it's essentially flatMap for Validated (but without the implications and syntactic sugar baggage that flatMap brings). If you wanted you could probably pretty easily change my version to do the empty list check first, as in your sketch, but the way I've written it feels a little more natural to me.
Footnote: I have no idea why the enrichment method for Option is named toValidNel while the one for Either is toValidatedNel—I hadn't noticed this before, probably because I hadn't used them in the same line before. This seems unfortunate, especially since we're stuck with it for a while now that Cats 1.0 is out.
Another footnote: note that you'll need the -Ypartial-unification compiler option enabled for traverse to work without type parameters if you're on 2.11.
Introduction
I had created a lovely one-liner:
Option("something").map(_ => Try("something else")).flatten.getOrElse("default")
which actually does not compile, with error:
Error:(15, 31) Cannot prove that scala.util.Try[String] <:< Option[B].
Option("").map(_ => Try("")).flatten.getOrElse("");}
^
so I had found a way around:
Option("something").flatMap(_ => Try("something else").toOption).getOrElse("default")
But, the problem
My colleague warned me, that my construction is actually loosing the error information. This is true, and in real-life application - not acceptable.
After getting rid of all the repetition I had ended up with:
implicit class CoolTry[T](t: Try[T]) extends StrictLogging {
def toOptionSE: Option[T] = t match {
case Success(s) => Some(s)
case Failure(ex) =>
logger.error(ex.getMessage, ex)
None
}
}
using:
Option("something").flatMap(_ => Try(new Exception("error")).toOptionSE).getOrElse("default")
Question
I believe there are many similar cases in every application and I simply do not know if either my approach is bad or Try().toOption is simply done wrong?
I understand that logging is a side effect, but while using Try I guess everyone does expect it if something goes wrong?
Can the implicit class be improved?
Is there any utility library handling Try().toOption my way?
Or what (other) approach should I take here?
Thanks!
Forcing logging every time you change a Try[T] to an Option[T] is an undesired effect IMO. When you do such a transformation you're explicitly admitting that you don't really care about the internals of the failure, if it happened. All you want is to access the result, if it exists. Most of the time you say "well, this is undesirable, I always want to log exceptions", but sometimes you simply only care about the end result, so dealing with an Option[T] can be good enough.
Or what (other) approach should I take here?
Using Either[A, B] is an option here, especially in Scala 2.12 when it became right biased. You can simply map over it and only at the end check if there was an error and then log (created with Scala 2.12.1):
val res: Either[Throwable, String] = Option("something")
.map(_ => Try("something else").toEither)
.getOrElse(Right("default"))
.map(str => s"I got my awesome $str")
Ideally (IMO) deferring the logging side effect to the last possible point would serve you better.
One possible improvement would be to make it crystal clear to the user of what is going on; between the implicit being injected somewhere by the compiler and the apparently "pure" name (toOptionSE) it may not be evident of what is going on for a second developer reading and/or modifying your code. Furthermore, you're fixing how you treat the error case and don't leave the opportunity to handle it differently from logging it.
You can treat errors by leveraging projection, like the failed projection defined over Try. If you really want to do this fluently and on one line, you can leverage implicit classes like this.
implicit class TryErrorHandlingForwarding[A](t: Try[A]) {
def onError(handler: Throwable => Unit): Try[A] = {
t.failed.foreach(handler)
t
}
}
// maybe here you want to have an actual logger
def printStackTrace: Throwable => Unit =
_.printStackTrace
Option("something").
flatMap(_ => Try(???).onError(printStackTrace).toOption).
getOrElse("default")
Also, here I'm assuming that for whatever reason you cannot use Try right from the start (as it's been suggested in a comment).
I'm fairly new to Scala so please be gentle.
In the app I'm currently building, I'm using Akka actors and I want to write some unit tests. I came across this official documentation for writing unit tests for Akka actors
but I couldn't understand exactly how it should work. In particular,
val actorRef = TestActorRef(new MyActor)
// hypothetical message stimulating a '42' answer
val future = actorRef ? Say42
val Success(result: Int) = future.value.get
result must be(42)
When I try that, I get not found: value Success, which is not surprising.
I then found this example of how to test Scala actors
val actorRef = TestActorRef[TickTock]
implicit val timeout = Timeout(5 seconds)
val future = (actorRef ? new Tick("msg")).mapTo[String]
val result = Await.result(future, timeout.duration)
Assert.assertEquals("processed the tick message", result)
, which admittedly is possibly old, but it is easy to understand and closer to what I normally use when I want to use Futures, and most importantly works. It does require me to declare a few implicits like the ActorSystem, timeout and such, which doesn't seem to be the case with the official way...
If possible, I'd like to use the method proposed by the official documentation, so I would appreciate it if someone could help me understand how it works (in particular the Success bit) and how to use it.
The answer to your question might be too long, because it is impossible to know how much Scala you actually know. I will try to make my answer as short as possible, but do not hesitate to ask for clarification at any point. I also apologize on behalf of the whole stackoverflow community for making you feel the need to apologize due to an apparent lack of skill before asking a question.
In Scala 2.10 a concept of Try was introduced. It is very similar to Option. Option is a concept of handling nulls. A value of type Option can take two forms: Some(value) or None. When you have an Optional value you can pattern match on it to see if it is a Some or a None and then act accordingly. Pattern matching occurs in many places in Scala and one of them is during the initialization of vals. Here are few examples:
val x = 10 // pattern 'x' on the LHS matches any value on the RHS so 'x' is initialized with 10
val Some(x) = Some(10) // pattern 'Some(x)' on the LHS matches any value of type 'Some' and binds it's value to x, so 'x' is yet again initialized with 10
Try is a concept of handling exceptions. A value of type Try can take two forms: Success(result) or Failure(throwable). When you have a value of type Try you can pattern match on it to see if it is a Success or a Failure.
This is what happens in your code (pattern matching on Success). In contrast to Option the two forms of Try are not in scope by default, which causes the compilation error. This will fix it:
import scala.util.{Try, Success, Failure}
Have your test extend the TestKit and then add "with ImplicitSender" and then you can do things like:
val yourActor = system.actorOf(Props[MyActor])
yourActor ! Say42
expectMsg(42)
Firstly it's not a good pattern to use get on futures value, this can raise an exception if there was a failure. You should use either Await.result, like in your seconds example, or use pattern matching to work with Success and Failure:
future match {
case Success(value) => // work with value
case Failure(ex) => // work with exception
}
to use Success and Failure import scala.util._ or scala.util.{Success, Failure}
Here is an official documentation for the latest release 2.2-M3.
Seeking a more elegant solution
I have this piece of code, I just use it in test cases where it isn't necessary to do any error handling. What it does is:
take an input list of strings
parse them using the DSJSonmapper.parseDSResult method
filters them and extracts the Right value from each Either (Left is an Exception)
The code is as follows:
def parseDs(ins: List[String]) = {
def filterResults[U, T](in: List[Either[U, T]]): List[T] = {
in.filter(y => y.isRight).map(z => z.right.get)
}
filterResults(ins.map(x => DSJsonMapper.parseDSResult(x)))
}
Now, I haven't done an awful lot of polymorphic functions, but this works. However I feel like it's a bit ugly. Has anyone got a better suggestion, how to accomplish the same thing.
I'm aware this is going to come down to a case of personal preference. But suggestions are welcome.
collect is made for exactly this kind of situation:
def filterMe[U,T](in: List[Either[U,T]]): List[T] = in.collect{
case Right(r) => r
}
In fact, it's so good at this you may want to skip the def and just
ins.map(DSJsonMapper.parseDsResult).collect{ case Right(r) => r }
Rex's answer is possibly a little clearer, but here's a slightly shorter alternative that parses and "filters" in a single step:
ins.flatMap(DSJsonMapper.parseDSResult(_).right.toOption)
Here we take the right projection of each parse result and turn that into an Option (which will be None if the parse failed and Some(whatever) otherwise). Since we're using flatMap, the Nones don't appear in the result and the values are pulled out of the Somes.