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, and by 0-arity function I mean () => T
I understand (I think) the conceptual difference, but probably I am missing something as I still have lots of questions:
- Why do we have the concept of
=>T
at all if we could always use () => T
?
- Is there any syntax/functional limitations of each? For now I found only that
=>
cannnot be used as a class field. Is this the only limitation?
- Is the generated code always the same for both?
- Should I always prefer
=>T
? And why?
- Is it correct to call
=>T
a type? It looks for me like it does not have any type representation in scala.
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 _
^