Skip to content

Instantly share code, notes, and snippets.

@sam
Last active December 26, 2015 05:39
Show Gist options
  • Save sam/7102162 to your computer and use it in GitHub Desktop.
Save sam/7102162 to your computer and use it in GitHub Desktop.
Example of passing a function to Future.map. This might not do what you think...
import scala.concurrent._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
import scala.language.postfixOps
object Main extends App {
def future = Future {
Thread sleep 5000
println("Future Completed")
1
}
def test = future map {
Thread sleep 1000
println("Map Function Completed?")
_ + 1
}
println("TEST:")
Await.result(test, 10 seconds)
// What you *think* is happening:
//
// I have a future. I'm going to map it.
// I'll pass it an anonymous function
// created using the placeholder.
// What's *actually* happening:
//
// I have a future. I'm going to map it.
// I'll execute a block of code that returns
// a new function created using the placeholder.
// It's easier to see if you break it up like this:
println("val speaker:")
val speaker = {
Thread sleep 1000
println("I'm executing after 1 second!")
}
// `speaker` is just a block of code. Nothing
// special right? You've just delineated it with
// curly braces. You get the result of it's
// expression though. It's not a future itself.
// It's not a function that takes an input.
// Here's a variation using the same example we
// passed to Future.map:
println("val mapper:")
val mapper = {
Thread sleep 1000
println("I'm executin' bauss!")
(_:Int) + 1
}
// What is the type of mapper?
// What is the significance of the curly-braces?
// The code within the block is just executed procedurally.
// It's not until the last line that you're returning a
// Function[Int,Int].
// So our original example is basically just:
println("MAPPER:")
Await.result(future map mapper, 10 seconds)
// The first and second lines of `mapper` have already
// been executed. So what we're passing here is not a
// Function0[Function1[Int,Int]] like we might have
// assumed in the original test. It's actually just
// Function1[Int,Int]!
// This can mean code you *thought* you were mapping
// can appear to execute out-of-order.
// What you really want is:
println("val function:")
val function = { i:Int =>
Thread sleep 1000
println("Now I'm inside an actual function!")
i + 1
}
println("FUNCTION:")
Await.result(future map function, 10 seconds)
// At this point I slap my forehead. Duh. How could
// I have missed it? map wouldn't take a Function0
// in the first place. The curly-braces were throwing me
// off. It all makes sense now. The real catch to this
// whole self-inflicted issue is that it only shows up
// when you're side-effecting within your map. Which is
// rare. In my case it was sending a message to an Actor
// (tell) before returning my mapped result. The tell
// ended up executing before my mapped Future finished.
// So TIL.
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment