Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Scala invoking no-parameter function with and without brackets is executed in different way

Tags:

scala

currying

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?

like image 660
myQs Avatar asked Feb 28 '15 13:02

myQs


4 Answers

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.

like image 198
acjay Avatar answered Oct 07 '22 18:10

acjay


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.

like image 23
lpiepiora Avatar answered Oct 07 '22 17:10

lpiepiora


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)
like image 35
myQs Avatar answered Oct 07 '22 16:10

myQs


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.

like image 35
Jason Avatar answered Oct 07 '22 18:10

Jason