I have following Currying function declaration:
def logString(count: Int)(fun:() => Unit) {
for (n <- 1 to count) { fun }
}
I call this function in this way:
logString(3) { () => print("I") }
The result is nothing - just no output.
Then I just add brackets after "fun" function invocation, inside the body of Currying function declaration:
def logString(count: Int)(fun:() => Unit) {
for (n <- 1 to count) { fun() }
}
The result becomes what is expected:
III
Is this some Scala bug, or there is some rule that I missed when learning Scala?
I know that there is rule that when you declare function like this: def myFun = 1 we can not invoke it with brackets - the compilation fails. But having different results when invoking a function with and without brackets seems more like a bug.
Am I right or I miss something about Scala?
Look at the type of fun
, it's fun: () => Unit
. You can think of that as meaning that when you call it with ()
, you get Unit
in return. Without explicitly calling it, fun
refers to the function as a value, not the result of calling it. This is the essence of the concept of higher-order functions.
If it had type fun: => Unit
, simply mentioning fun
would cause it to be executed, in which case there would be no way to refer the function as a value.
When you have such a declaration
val x = 10
this is a value definition. The value x can be an integer like in this case, but it can also be a function.
val y = () => println("i'm a function")
However either way, if you call it without parenthesis nothing will happen.
scala> val x = 10
x: Int = 10
scala> val y = () => println("i'm a function")
y: () => Unit = <function0>
scala> x
res0: Int = 10
scala> y
res1: () => Unit = <function0>
When you have a function definition like this:
def z() = println("i'm a function def")
Then you can omit parenthisis and call it without it.
scala> def z() = println("i'm a function def")
z: ()Unit
scala> z
i'm a function def
In your case fun
is like a value definition (it's a value parameter).
What happens is that, when Scala evaluates your for
expression it will just do nothing with fun
.
Just the same as if you did y
vs y()
from the example above.
I just wanted to share the information summarized by me based on the very helpful answers answers above and some additional research. Might be would be helpful for someone else also. Functions can be declared in two ways in Scala: - "call-by-name" - they are represented in the byte code as normal Java functions in a straightforward way. - "call-by-value" - from Scala's abstract point of view they are stored in variables. Actually in the Byte code they are stored in classes implementing Single Abstract Method interfaces (SAM) and passed around as method parameters or as normal variables.
When we invoke a "call-by-name" function that does not take parameters it is always executed no matter how we call it with or without brackets. So now myFunction and myFunction() is just the same. When we invoke a "call-by-value" function that does not take parameters we have two cases: - when we do not have brackets after it - myFunction - we just refer to the variable pointing to the function without executing function itself. - when we have brackets - myFunction() - we actually call (execute) the function.
Different ways to declare function:
def myFunction = 5 * 5
This is call-by-name function. Declared this way no brackets allowed when calling it. So calling myFunction() will not compile. Call it this way: myFunction
def myFunction() = 5 * 5
This is call-by-name function. Can call the function with and without brackets - the effect is the same. So myFunction and myFunction() is just the same.
def myFunction = () => 5 * 5
This is call-by-value function (even when declared as def not val) . When calling it with brackets - myFunction() - function is executed, when calling it without brackets - myFunction - function is NOT executed - just val holding it is being mentioned.
Similarly if we declare function as other function's parameter:
def enclosingFunc(myFunction: => Void)
This is call-by-name function. Inside enclosing function it will be executed only if called without brackets - myFunction. With brackets - myFunction() - will not compile.
In this case enclosingFunc could be called this way:
enclosingFunc(n = 1; n +=1)
def enclosingFunc(myFunction: () => Int)
This is call-by-value function. It matters how we invoke it in the body of enclosing function. If invoke it without brackets - myFunction - it will NOT be executed, but we just refer to the object holing it. If invoke it with brackets - myFunction() - it will be called and executed.
In this case enclosingFunc could be called only in this way:
enclosingFunc( () => n = 1; n +=1)
In the first example the function fun
doesn't isn't invoked, it juts sort of sits there. Adding the parenthesis cause the passed-in function to be evaluated.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With