Getting lost in Scala Futures - scala

I'm slowly wrapping my brain around Futures in Scala, and have a bit of a layer cake going on that I'm trying to unravel.
The specific use case is a DeferredResolver in sangria-graphql + akka. I've stolen their demo code, which looks like this
Future.fromTry(Try(
friendIds map (id => CharacterRepo.humans.find(_.id == id) orElse CharacterRepo.droids.find(_.id == id))))
and added my own modification to it. Theirs does an in-memory lookup, whereas mine asks something of another actor:
Future.fromTry(Try(
accountIds match {
case h :: _ =>
val f = sender ? TargetedMessage(h)
val resp = Await.result(f, timeout.duration).asInstanceOf[TargetedMessage]
marshallAccount(resp.body)
case _ => throw new Exception("Not found")
}
))
The pertinent piece here is that I pick the first element in the list, send it to an ActorRef that I got elsewhere and wait for the result. This works. What I'd like to do, however, is not have to wait for the result here, but return the whole thing as a Future
Future.fromTry(Try(
accountIds match {
case h :: _ =>
sender ? TargetedMessage(h) map {
case resp:TargetedMessage => marshallAccount(resp.body)
}
case _ => throw new Exception("Not found")
}
))
This doesn't work. When this is consumed, instead of being of type Account (the return type of function marshallAccount, it's of type Promise. If I understand correctly, it's because instead of having a return type of Future[Account], this has a type of Future[Future[Account]]
How do I flatten this?

You are looking at the wrong API method. Future.fromTry is used to create an immediately resolved Future, meaning the call is not actually asynchronous. Dive into the implementation of Future.fromTry which will take you to:
def fromTry[T](result: Try[T]): Promise[T] = new impl.Promise.KeptPromise[T](result)
A promise kept is basically something that has already happened, so just like Future.successful this is just used to ensure the right return type or similar, it's not actually a way to make something async.
The reason why the return type is Future[Future[Something]] is because you are trying to wrap something that already returns a future into another future.
The ask pattern, namely sender ? TargetMessage(h) is a way to ask something of an actor and await for a result, which will return a future.
The correct way to approach this:
val future: Future[Account] = accountIds match {
case h :: _ => sender ? TargetedMessage(h) map (marshallAccount(_.body)
case _ => Future.failed(throw new Exception("Not found"))
}
Basically you need to use Future.failed to return a failed future from an exception if you want to keep the return type consistent. It's worth reviewing this tutorial to learn a bit more about Futures and how to write application logic with them.

Related

Is it possible to call a generically-typed function by passing in a class specified in a map?

Asking here because I'm pulling out my hair trying to figure out what exactly it is I need to do here.
I'm writing a batch-processing endpoint that attempts to convert the body of a request to a specific Scala case class before executing the logic within the endpoint itself.
This is as far as I currently got. First, I have a function executeWithType that takes a generic type, a controller method, and the request body and executes the controller method after converting the request body to the provided type. The request param is available in a scope outside this function.
def executeWithType[A](action: () => Action[A], batchRequest: BatchRequest): Future[Result] = {
action()(request.map(_ => batchRequest.body.map(_.as[A]).get))
}
Then, I have some code that checks what endpoint to call and what type to cast to depending on what's in the BatchRequest itself.
val res: Future[Result] = (batchRequest.method, batchRequest.endpoint) match {
case ("POST", "/endpoint1") => {
executeWithType[EndpointOneType](controller.endpointOne _, batchRequest)
}
case ("POST", "/endpoint2") => {
executeWithType[EndpointTwoType](controller.endpointTwo _, batchRequest)
}
case _ => Future.successful(NotFound)
}
The above works perfectly fine - however, I want to avoid this sort of tuple-matching with individual cases if possible, and specify a Map that does this instead. In my ideal world, the end result of the code block immediately above would look like this:
val actions = Map(
Seq("POST", "/endpoint1") -> (controller.endpointOne _, EndpointOneType),
Seq("POST", "/endpoint2") -> (controller.endpointTwo _, EndpointTwoType)
)
val res = actions.get(Seq(batchRequest.method, batchRequest.endpoint)) match {
case Some(action) => {
executeWithType[action._2](action._1, batchRequest)
}
case _ => Future.successful(NotFound)
}
Is this possible at all? I've been trying to fight with it but my understanding of reflection in Scala is really weak, so I'm not sure exactly how I'd go about doing this. I've tried a bunch of classOf and typeTag and Class[_] stuff but I'm basically swinging in the dark. Hoping someone more knowledgeable than I am could help me out.
The big things are:
What needs to go in the second space of the tuple in the value of the Map? How do you pass a Class variable?
How do we use that class-as-a-variable to call a generically typed method?
How do we use that class-as-a-variable to call a generically typed method?
You can't. But I'd like to suggest an alternate solution.
Just define a local class instead of tuples:
class RequestAction[A](action: () => Action[A]) {
def apply(request: BatchRequest) = executeWithType(action, request)
}
val actions = Map(
Seq("POST", "/endpoint1") -> new RequestAction(controller.endpointOne _), // type parameter is inferred
Seq("POST", "/endpoint2") -> new RequestAction(controller.endpointTwo _)
)
val res = actions.get(Seq(batchRequest.method, batchRequest.endpoint)) match {
case Some(action) => action(batchRequest)
case _ => Future.successful(NotFound)
}
(while this depends on code not shown in the question, it looks likely that you can simplify by passing Action[A] instead of () => Action[A]).

Chaining together operations on an Option to a Future, then back to an Option?

I'm writing an authentication client that takes an Option[Credentials] as a parameter. This Credentials object has a .token method on it which I will then use to construct an HTTP request to post to an endpoint. This returns a Future[HttpResponse], which I then need to validate, unmarshal, and then convert back to my return type, which is an Option[String].
My first thought was to use a for comprehension like this:
val resp = for {
c <- creds
req <- buildRequest(c.token)
resp <- Http().singleRequest(req)
} yield resp
but then I found out that monads cannot be composed like that. My next thought is to do something like this:
val respFut = Http().singleRequest(buildRequest(token))
respFut.onComplete {
case Success(resp) => Some("john.doe")//do stuff
case Failure(_) => None
}
Unfortunately onComplete returns a unit, and map leaves me with a Future[Option[String]], and the only way I currently know to strip off the future wrapper is using the pipeTo methods in the akka framework. How can I convert this back to just an option string?
Once you've got a Future[T], it's usually good practice to not try to unbox it until you absolutely have to. Can you change your method to return a Future[Option[String]]? How far up the call stack can you deal with futures? Ideally it's all the way.
Something like this will give you a Future[Option[String]] as a result:
val futureResult = creds map {
case Some(c) => {
val req = buildRequest(c.token)
val futureResponse = Http().singleRequest(req)
futureResponse.map(res => Some(convertResponseToString(res)))
}
case None => Future(None)
}
If you really need to block and wait on the result, you can do Await.result as described here.
And if you want to do it in a more monadic style (in a for-comprehension, like you tried), cats has an OptionT type that will help with that, and I think scalaz does as well. But whether you want to get into either of those libraries is up to you.
It's easy to "upgrade" an Option to a Future[Option[...]], so use Future as your main monad. And deal with the simpler case first:
val f: Future[Option[String]] =
// no credential? just wrap a `None` in a successful future
credsOpt.fold(Future.successful(Option.empty[String])) {creds =>
Http()
.singleRequest(buildRequest(creds.token))
.map(convertResponseToString)
.recover {case _ => Option.empty[String]}
}
The only way to turn that future into Option[String] is to wait for it with Await.result(...)... but it's better if that future can be passed along to the next caller (no blocking).
I'm not 100% certain about what all your types are, but it seems like you want a for comprehension that mixes option and futures. I've often been in that situation and I find I can just chain my for comprehensions as a way to make the code look a bit better.
val resp = for {
c <- creds
req <- buildRequest(c.token)
} yield for {
resp <- Http().singleRequest(req)
} yield resp
resp becomes an Option[Future[HttpResponse]] which you can match / partial func around with None meaning the code never got to execute because it failed its conditions. This is a dumb little trick I use to make comprehensions look better and I hope it gives you a hint towards your solution.

having trouble composing Scala Future from multiple Futures of different types

I have two functions: one returns a Future[Thing Or Exception] and another that returns Future[Boolean. I want a function that calls both and returns Future[Thing Or Exception]. If the boolean function returns false I want to return an exception, else the return of the other function.
I have code like this but a) I hate the cast and b) when run on the "boolean gets true" path I get this error when I eventually Await.result on the return in my test code: "Promise$DefaultPromise cannot be cast to org.scalatic.Or".
def thingFuture: Future[Thing Or Exception]
def boolFuture: Future[Boolean]
def combineFutures: Future[Thing Or Exception] = {
val result = boolFuture.map {x =>
x match {
case true => thingFuture
case false => Exception
}
}
// without the cast compiler says result is of type Future[Object]
result.asInstanceOf[Future[Thing Or Exception]]
}
I've also tried this but it gets the same Promise error on the success path
def combineFutures: Future[Thing Or Exception] = {
val result = boolFuture.map {x =>
x match {
case true => thingFuture.map { y =>
y match {
case Good(thing) => thing
case Bad(exception) => exception
}
case false => Exception
}
}
}
Can anyone tell me how to compose two futures with different return types? Thanks!
Every future can be completed with failed state in case exception has occurred, so you can simply return thingFuture in the "happy path" and throw an exception in case boolean is false. This will return a Future.failed with the underlying exception.
val result = boolFuture.flatMap {x =>
x match {
case true => thingFuture
case false => throw new Exception("whatever")
}
}
Note the flatMap instead of map. Because we map the underlying value of one future into a yet another future, by using simple map we would wind up with Future[Future[Thing]].
Also note that instead of throwing an exception, you could also return a Future.failed(throw new Exception("whatever")) and the result would be the same - in both case you get a failed future.
EDIT: I just realized Or comes from scalactic, which I never used, but the philosophy remains the same. You need to flatMap your boolean future and your ThingOrException future in order to wind up with Future[ThingOrException]. If you ever find yourself in a situation where you need to flatMap a Future, but one of the case clauses returns an ordinary value (e.g. in case of true return Future[Thing], in case of false return just Exception) then you can wrap the ordinary value into a future. This way all branches return a future and flatMap will work correctly. For example:
val someOtherFuture = Future(43)
val someOrdinaryValue = 44
Future(someInteger).flatMap {
case 42 => someOtherFuture
case _ => Future(someOrdinaryValue)
}
In order to simplify things for the runtime machinery a bit, you can also write Future.successful(someOrdinaryValue) in which case no background computation is started.
As far as I can tell from Scalatic documentation, you can get an instance of Right Or Left by either Good(Right) or Bad(Left).
That means the composition can potentially look like this:
boolFuture.flatMap(b => if (b) thingFuture else Future.successful(Bad(new Exception())))
The types should unify to Future[Or[Thing, Exception]]

Aliasing objects from expensive statements in Scala pattern match

I have an expensive case statement which needs to hit the database to determine a complete match. If there is a match, the result from the aforementioned call must be used to perform further operations:
def intent = {
case request # GET(Path(Seg(database :: Nil))) if recordsFrom(database) != Nil =>
renderOutput(recordsFrom(database))
case ...
}
I would like to call recordsFrom(database) only once. In the above example, it is called twice. It seems like I should be able to apply some alias to the statement?
Lawrence, from what I'm seeing you're using Unfiltered to handle a RESTful request but you've also combined a database lookup with that response filtering. I would advise you not to do that. Instead I'd arrange things as following:
val dbReqCommand = new DBRequestCommand(myDbConPool)
def intent ={
case req # GET(Path(Seq(database :: Nil))) => dbReqCommand(req, database)
}
Wherein you've encapsulated the db requests in an object that you could substitute out for testing purposes (think integration tests without a DB backend.) Within the request handler you might then put in the response:
Option(recordsFrom(database)) match{
case Some(value) => OK ~> renderOpupt(value)
case None => //an error response or Pass
}
That way you might have something along the lines of:
trait DBReqPlan{
def dbReqCommand: RequestCommand[String]
def intent ={
case req # GET(Path(Seq(database :: Nil))) => dbReqCommand(req, database)
}
}
which is easier to test against and work with.
What's wrong with:
def intent = {
case request # GET(Path(Seg(database :: Nil))) =>
val records = recordsFrom(database)
if(!records.isEmpty){
renderOutput(records)
} else {
...
}
case ...
You can move the body of the first case to a different function if you want to avoid having too many nested blocks.

Processing Scala Option[T]

I have a Scala Option[T]. If the value is Some(x) I want to process it with a a process that does not return a value (Unit), but if it is None, I want to print an error.
I can use the following code to do this, but I understand that the more idiomatic way is to treat the Option[T] as a sequence and use map, foreach, etc. How do I do this?
opt match {
case Some(x) => // process x with no return value, e.g. write x to a file
case None => // print error message
}
I think explicit pattern matching suits your use case best.
Scala's Option is, sadly, missing a method to do exactly this. I add one:
class OptionWrapper[A](o: Option[A]) {
def fold[Z](default: => Z)(action: A => Z) = o.map(action).getOrElse(default)
}
implicit def option_has_utility[A](o: Option[A]) = new OptionWrapper(o)
which has the slightly nicer (in my view) usage
op.fold{ println("Empty!") }{ x => doStuffWith(x) }
You can see from how it's defined that map/getOrElse can be used instead of pattern matching.
Alternatively, Either already has a fold method. So you can
op.toRight(()).fold{ _ => println("Empty!") }{ x => doStuffWith(x) }
but this is a little clumsy given that you have to provide the left value (here (), i.e. Unit) and then define a function on that, rather than just stating what you want to happen on None.
The pattern match isn't bad either, especially for longer blocks of code. For short ones, the overhead of the match starts getting in the way of the point. For example:
op.fold{ printError }{ saveUserInput }
has a lot less syntactic overhead than
op match {
case Some(x) => saveUserInput(x)
case None => printError
}
and therefore, once you expect it, is a lot easier to comprehend.
I'd recommend to simply and safely use opt.get which itself throws a NoSuchElementException exception if opt is None. Or if you want to throw your own exception, you can do this:
val x = opt.getOrElse(throw new Exception("Your error message"))
// x is of type T
as #missingfaktor says, you are in the exact scenario where pattern matching is giving the most readable results.
If Option has a value you want to do something, if not you want to do something else.
While there are various ways to use map and other functional constructs on Option types, they are generally useful when:
you want to use the Some case and ignore the None case e.g. in your case
opt.map(writeToFile(_)) //(...if None just do nothing)
or you want to chain the operations on more than one option and give a result only when all of them are Some. For instance, one way of doing this is:
val concatThreeOptions =
for {
n1 <- opt1
n2 <- opt2
n3 <- opt3
} yield n1 + n2 + n3 // this will be None if any of the three is None
// we will either write them all to a file or none of them
but none of these seem to be your case
Pattern matching is the best choice here.
However, if you want to treat Option as a sequence and to map over it, you can do it, because Unit is a value:
opt map { v =>
println(v) // process v (result type is Unit)
} getOrElse {
println("error")
}
By the way, printing an error is some kind of "anti-pattern", so it's better to throw an exception anyway:
opt.getOrElse(throw new SomeException)