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

前端 未结 3 701
我在风中等你
我在风中等你 2021-01-23 18:09

The program looks like this ...

object Delay{

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

    def time()={
        println(\"Getting time          


        
相关标签:
3条回答
  • 2021-01-23 18:51

    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.

    0 讨论(0)
  • 2021-01-23 19:00

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

    0 讨论(0)
  • 2021-01-23 19:08

    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
    
    0 讨论(0)
提交回复
热议问题