Why is this function called multiple times?

scala

Solution

Your `x` is not a function, it is a by-name parameter, and its type is a parameterless method type.

Parameterless method type means the same as `def x`, something that is evaluated every time you reference it. By reference, we mean `x` and not `x.apply()` or `x()`.

The expression you're passing to your function `f` is evaluated every time `x` is referenced in `f`. That expression is the whole thing in braces, a block expression. A block is a sequence of statements followed by the result expression at the end.

Here's another explanation: https://stackoverflow.com/a/13337382/1296806

But let's not call it a function, even if it behaves like one under the covers.

Here is the language used in the spec:

http://www.scala-lang.org/files/archive/spec/2.11/04-basic-declarations-and-definitions.html#by-name-parameters

It's not a value type because you can't write `val i: => Int`.

It was a big deal when they changed the implementation so you could pass a by-name arg to another method without evaluating it first. There was never a question that you can pass function values around like that. For example:

scala> def k(y: => Int) = 8
k: (y: => Int)Int

scala> def f(x: => Int) = k(x)   // this used to evaluate x
f: (x: => Int)Int

scala> f { println("hi") ; 42 }
res8: Int = 8

An exception was made to "preserve the by-name behavior" of the incoming x.

This mattered to people because of eta expansion:

scala> def k(y: => Int)(z: Int) = y + y + z
k: (y: => Int)(z: Int)Int

scala> def f(x: => Int) = k(x)(_)  // normally, evaluate what you can now
f: (x: => Int)Int => Int

scala> val g = f { println("hi") ; 42 }
g: Int => Int = <function1>

scala> g(6)
hi
hi
res11: Int = 90

The question is how many greetings do you expect?

More quirks:

scala> def f(x: => Int) = (1 to 5) foreach (_ => x)
f: (x: => Int)Unit

scala> def g(x: () => Int) = (1 to 5) foreach (_ => x())
g: (x: () => Int)Unit

scala> var y = 0
y: Int = 0

scala> y = 0 ; f { y += 1 ; println("hi") ; y }
hi
hi
hi
hi
hi
y: Int = 5

scala> y = 0 ; g { y += 1 ; println("hi") ; () => y }
hi
y: Int = 1

scala> y = 0 ; g { () => y += 1 ; println("hi") ; y }
hi
hi
hi
hi
hi
y: Int = 5

Functions don't cause this problem:

scala> object X { def f(i: Int) = i ; def f(i: => Int) = i+1 }
defined object X

scala> X.f(0)
res12: Int = 0

scala> trait Y { def f(i: Int) = i }
defined trait Y

scala> object X extends Y { def f(i: => Int) = i+1 }
defined object X

scala> X.f(0)
<console>:11: error: ambiguous reference to overloaded definition,
both method f in object X of type (i: => Int)Int
and  method f in trait Y of type (i: Int)Int
match argument types (Int)
              X.f(0)
                ^

Compare method types:

http://www.scala-lang.org/files/archive/spec/2.11/03-types.html#method-types

This is not a pedantic distinction; irrespective of the current implementation, it can be confusing to think of a by-name parameter as "really" a function.

Problem

In this function "f" : ``` def f(x: => Int) : Int = x * x * x //> f: (x: => Int)Int var y = 0 //> y : Int = 0 f { y += 1 println("invoked") y } //> invoked //| invoked //| invoked //| res0: Int = 6 ``` "f" is invoked same amount of times as "x" parameter is multiplied. But why is function invoked multiple times ? Should "f" not expand to `1 * 1 * 1` not `1 * 2 * 3` ?

Original source

Related problems