The program looks like this ...
object Delay{
def main(args: Array[String]){
delayed(time())
}
def time()={
println(\"Getting time
The reason why you see this execution order, is because t
is a by-name parameter in your code:
def delayed(t: => Long)
If you defined your delayed
method with a by-value parameter like so:
def delayed(t: Long)
the time()
function would have been evaluated before the call to delayed
, and you would get the following output instead:
Getting time in nanoseconds :
In delayed Method
Param : 139735036142049
The trick is that by-name parameters are called only when they're used, and every time they're used. From the Scala docs:
By-name parameters are only evaluated when used. They are in contrast to by-value parameters.
By-name parameters have the advantage that they are not evaluated if they aren’t used in the function body. On the other hand, by-value parameters have the advantage that they are evaluated only once.
t/time
value will be evaluated before printing param.
so it prints println("Getting time in nanoseconds:")
before printing println("Param : "+t)
IMHO the current scala doc, within the link provided by Zoltan, is misleading and confusing. By-name parameters have the advantage of repetitive read / call / evaluation, and are used mainly for that purpose. The delayed evaluation has to do with lazy vals, that is a different topic. The delayed evaluation of by-name, when passed as var / closure / anonymous_function, is just a collateral effect of the repetitiveness - given as an example, in the same scala doc, under the from of a whileLoop example.
By-name parameter behavior depends on what you pass as actual param -
.
def two[A](a: => A): List[A] = List(a, a) // two references
def two_iter[A](a: => A) { (1 to 2) foreach { x => a } } // two references
def two_lazy[A](a: => A) = { lazy val b = a; List(b, b) // one lazy reference
def two_delayed[A](a: => A): List[A] = { val l = List(a); Thread.sleep(5000); a :: l } // two references with delay
val x = 5; two(5); two(x) // (5, 5) only once
var z = 5; val f = Future { two_delayed(z) }; Thread.sleep(1000); z += 1; f.onSuccess { case result => println(result) } // (6, 5) two reads
two { println("in"); 5 } // (5, 5) called twice
var t = 0; two { println("in"); t += 1; t } // (1, 2) called twice
two_iter { println("in"); 5 } // called twice
two_lazy { println("in"); 5 } // (5, 5) called once