Sula
Sula

Reputation: 76

Why does scala call the method passed to println before printing the line it is called in?

The program looks like this ...

object Delay{

    def main(args: Array[String]){
        delayed(time())
    }

    def time()={
        println("Getting time in nanoseconds : ")
        System.nanoTime
    }

    def delayed(t: => Long)={
        println("In delayed Method")
        println("Param : "+t)
    }
}

And the output is ...

    In delayed Method
    Getting time in nanoseconds :
    Param : 139735036142049

My question is why does the word "Param :" print after the "Getting time ..." and not like,

    In delayed Method
    Param : 
    Getting time in nanoseconds : 139735036142049

Upvotes: 1

Views: 794

Answers (3)

Zoltán
Zoltán

Reputation: 22156

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.

Upvotes: 4

Volty De Qua
Volty De Qua

Reputation: 290


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 -

  • if you pass a val(ue)/constant it will be evaluated in advance,
  • if you pass a var its value will be read each time the by-name is referenced by the runtime code
  • if you pass a closure / anonymous_function it will get called each time the by-name is referenced by the runtime code

.

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

Upvotes: 0

vkt
vkt

Reputation: 1459

t/time value will be evaluated before printing param. so it prints println("Getting time in nanoseconds:") before printing println("Param : "+t)

Upvotes: 0

Related Questions