Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Future mapping transparently split in two functions when using anonymous parameters

Tags:

scala

future

I am stuck with something I observed with Scala futures and I cannot figure out what happens here. I am mapping a future to another result, nothing fancy here:

import scala.concurrent.{Await, Future}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object Example extends App {
  val f = Future {
    Thread.sleep(1000)
    println("Future: " + Thread.currentThread + " (" + 
        System.currentTimeMillis + ")")
    "future"
  }
  val g = f map { x =>
    println("Map future: " + Thread.currentThread + 
        " (" + System.currentTimeMillis + ")")
    "mapped " + x
  }
  println(Await.result(g, 5 seconds))
}

Since the function I map the future to is depending on the result of f, I expect the function to be only triggered after the computation of f is complete. This is also what I can observe with the above code. However, when I change the function for g to carry anonymous parameters, this behavior changes:

val g = f map {
  println("Map future: " + Thread.currentThread + " (" + 
      System.currentTimeMillis + ")")
  "mapped " + _
}

Even though the result of g depends on the result of f, the method is triggered before the computation of f completes. It seems as if the method is split to a part before and after the input value is actually required. Also, the first part of the thread is executed in main. Is this the compiler that does something fancy here? For me, this comes pretty unexpected. Or is this behavior expressed somewhere in Scala? I could not find it in the sources, though.

Anybody knows what is going on here? I am using Scala 2.10.

like image 753
Rafael Winterhalter Avatar asked May 10 '26 01:05

Rafael Winterhalter


1 Answers

It may surprize you, but println is executed during lambda construction time:

List(1,2,3).map { 
    println("Hi!")
    "Processing " + _ 
}

// Hi! 
// res4: List[String] = List(Processing 1, Processing 2, Processing 3)

As you can see Hi! is outputed only once.

That is because your code is semantically identical to:

def constructLambda() = {
  // do something, e.g. println
  // now return actual lambda
}
val lambda = constructLambda()
xs map (lambda) // now trigger previously *lazy* piece of code
// or even this, like in your snippet
xs map lambda
like image 118
om-nom-nom Avatar answered May 12 '26 07:05

om-nom-nom



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!