Thursday, July 28, 2011

Scala by-name parameter

I was reading the section "Call-by-Name" in the book "Begining Scala" by David Pollak,
trying to get my head around by-name parameters. He gave an example,

def nano() = {
    println("Getting nano")
    System.nanoTime
}

def delayed(t: => Long) = { // => indicates a by-name parameter
    println("In delayed method")
    println("Param: "+t)
    t
}

println(delayed(nano()))

Coming from Java and used to call-by-reference, I was expecting the output to be

Getting nano
In delayed method
Param: 4513758999378
4513758999378     // same value as Param

but the output was

In delayed method
Getting nano
Param: 4475258994017
Getting nano
4475259694720     // different value from Param

Re-reading that section a couple of times still doesn't ring a bell (the book is really good though).
Googling "scala by-name parameters" returns long examples and explanations
on the subject, and more confusion for an absolute Scala beginner like me.

Referring to the Scala Language Specification, section 4.6.1 By-Name Parameters finally defreezes my brain.

... argument is not evaluated at the point of function application, but instead is evaluated at each use within the function.

Ok. Got it. Back to the example,

def delayed(t: => Long) = {
    println("In delayed method")
    println("Param: "+t) // t or nano() used, so "Getting nano" printed,
                         // then print "Param: " and the return of nano(), e.g. System.nanoTime
    t                    // t or nano() used again, thus print "Getting nano" and the System.nanoTime
                         // would have now elapsed
}