Some questions about difference between call-by-name and 0-arity functions

前端 未结 1 618
日久生厌
日久生厌 2020-12-18 00:42

There are some discussions here about this, but I have some specific questions I wasn\'t able to find an answer for. So, by call-by-name, I mean =>T type, an

相关标签:
1条回答
  • 2020-12-18 01:25

    1) It's just more handy to use it, especially inside DSLs:

    def printAndGet[T](f: => T) = {
      val res = f
      println(res + " printed") 
      res
    }
    
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    val k = printAndGet {
      val a = 5
      5 * a 
    }
    
    // Exiting paste mode, now interpreting.
    
    25 printed
    k: Int = 25
    

    2) => T can only be a parameter of method or function. And actually => T and () => T aren't interchangable:

    scala> def aaa(f: => String) = f
    aaa: (f: => String)String
    
    scala> val a: Function1[() => String, String] = aaa _
    <console>:8: error: type mismatch;
     found   : (=> String) => String
     required: (() => String) => String
           val a: Function1[() => String, String] = aaa _
                                                    ^
    

    Thanks to @som-snytt, fоund this one:

    scala> object O { def f(i: Int) = i; def f(i: => Int) = i + 1 }
    defined object O
    
    scala> O.f(5)
    res12: Int = 5
    
    scala> O.f(5: (=> Int))
    <console>:1: error: no by-name parameter type allowed here
           O.f(5: (=> Int))
               ^
    

    Even this which should work if it compiles - but it doesn't (scala 2.11.2, 2.11.5 REPL just crashes):

    scala> val k: (=> Int) => Int = O.f _
    k: (=> Int) => Int = <function1>
    
    scala> k(5) //should be 6
    res18: Int = 5 //WTF?
    

    Last one seems like a bug

    3) Not exactly, if you want the same, just convert => T into () => T:

    scala> def aaa(f: => String) = {f _}
    aaa: (f: => String)() => String
    

    Bytecode may also differ. For instance, compiler will more likely inline code from => T without generating lambda for it. So, the key difference is that () => T is actually an object (first class citizen), => T isn't.

    4) see 1, but sometimes you may need to ensure that user knows that computation might be delayed - () => T is better then.

    5) It's part of a type signature, just look at eta-expansion of:

    scala> def aaa(f: => String) = {f}
    aaa: (f: => String)String
    
    scala> aaa _ //convert method into a function
    res7: (=> String) => String = <function1>
    
    scala> val a: ( => String) =>  String = aaa _
    a: (=> String) => String = <function1>
    

    However scala doesn't recognize it as independent type:

    scala> val a: Function1[( => String), String] = aaa _
    <console>:1: error: no by-name parameter type allowed here
           val a: Function1[( => String), String] = aaa _
                              ^
    
    0 讨论(0)
提交回复
热议问题