Last active
December 26, 2015 05:39
-
-
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...
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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