9 comments

[ 5.5 ms ] story [ 43.6 ms ] thread
Future objects are the simplest way to write these workloads because they map directly to a very simple 2-step model

1) I want this, get started 2) I'll check when I need this, then I'll wait

This is what I do when I want to order pizza for pickup and it's easier to debug most of the time - they're only annoying when the pizzas ordered were never picked up (& you get a memory leak, eventually).

This is wrong. Well not wrong but it doesn't work the way it seems the author thinks it does. For comprehensions de-sugar in a way that isn't really great. See the first answer here. http://stackoverflow.com/questions/19045936/scalas-for-compr... .

Basically what he means with that code is: Do four things in parallel and then return the result. What his code ACTUALLY does is do 4 things in sequence in a non-blocking way. This isn't bad (certainly better than blocking for each step) but it misses the real value. He should fire the for futures and then use traverse or Future.sequence to combine them. It is uglier but actually achieves the intended result.

That is, he's using a monadic interface when an applicative interface is better. Facebook's HAXL project is all about this sort of thing.
Fair point. The for-comprehension is not quite as magical as I describe it. However, as long as the futures are created outside of the comprehension, the behavior is nearly as described. I'll include a note about it.
Cool. Like I mentioned this is still better than the before case. This is a super confusing area of Futures for most people, especially the newer Scala users. I got burnt a couple of times by this. It might not be obvious how creating the future outside of the comprehension changes the behavior the someone new to the topic. This is one of those gotchas that can make Scala frustrating for new users.
No, they are right, it would be a sequential operation if the individual steps depended on each other which is not the case. All the four tasks will be computed in parallel and then aggregated to give the result.

For comprehensions reduce a lot of syntactic noise and are good to have although you need to make sure that you spawn futures outside of it.

The issue is that this:

  val future1 = asyncService1()
  val future2 = asyncService2()
  val future3 = asyncService3()
  val future4 = asyncService4()

  val resultFuture:Future = for { //For-comprehension
    r1 <- future1
    r2 <- future2
    r3 <- future3
    r4 <- future4
  } yield (someOperation(r1, r2, r3, r4))
looks a lot like this

  val resultFuture:Future = for { //For-comprehension
    r1 <- asyncService1()
    r2 <- asyncService2()
    r3 <- asyncService3()
    r4 <- asyncService4()
  } yield (someOperation(r1, r2, r3, r4))
But the second one will be sequential. This is a common trap for new Scala futures users. You are right (as is the op below) that the first one work the way you expect. It is just easy for new users who don't understand how the de-sugaring resolves for get "caught."
Yeah but that's my point they are doing it right.They are not falling into the trap ;)
You are right. I jumped on it without giving the author the benefit of the doubt. This is one of those things that I personally have been burned by, and I wanted to save other from falling victim to the same mistake.