ZchGarinch
ZchGarinch

Reputation: 327

Is def considered a closure in Scala?

I want to understand the difference between the closure declared as val and the one declared as method (with the def kyeword). What's exactly the difference between theses two functions, is the ep method a closure ?

scala > var more=10

scala > val phi= (x:Int)=>x+more

scala > def ep(x:Int):Int= x+more

Upvotes: 3

Views: 744

Answers (1)

Ra Ka
Ra Ka

Reputation: 3055

A function object that captures free variables, and is said to be “closed” over the variables visible at the time it is created is called closure. For example:

var foo = 10
val bar = (x:Int) => x+foo

Here, foo is free variable in function literal and hence the function literal is open term. As a result, val bar is a closure since function value (object) is created with open term foo.

Now, lets start with different between val and def in term of function definition.

In scala, function is a value and you can assign it to variable.

When you define a function with val, you are defining it with a function literal as val bar = (x:Int) => x+foo, which return a function object and assign it as value to bar. In case of val, the function value is evaluated as it is defined. That means, function literal (x:Int) => x+foo is evaluated to function value with free variable foo and is stored in bar variable as closure.

//In the following snippet, a function literal is evaluated to object Function1 and assigned to val bar. 
scala> var foo = 10
foo: Int = 10

scala> val bar = (x: Int) => x + foo
bar: Int => Int = <function1>         //Function1 object is returned

Since, bar is a value and is evaluated as it is defined, it will always refer to same object in the memory whenever accessed.

scala> bar eq bar       //because both instance refer to same instance. 
res11: Boolean = true

On the other hand, you define a method with def and method is not a function in Scala. According to Scala language specification, method do not have type in Scala hence it cannot be used as value. For example, you cannot do as:

val bar = {def foo(x:Int): Int = x + 1 }

However, according to Specification, if method name is used as value, then Scala implicitly converts it to corresponding function type with ETA Expression. e.g. method def a: Int is converted as a: => Int. That means, every time you call method, it returns a function value.

scala> def foo():Int = 1
a: ()Int

scala> val bar:( ()=> Int) = foo
bar: () => Int = <function0>        //foo return Function0

//Note, val bar = foo, will assign the value returned by foo instead of returning function, so specify type. 

Because of this, method can be used as function. For example, when ever some method or function require a function type as argument, you can provide def method.

scala> val foo = (x:Int, double:Function1[Int, Int]) => double(x)
foo: (Int, Int => Int) => Int = <function2>

scala> def double(x:Int):Int = x * 2
double: (x: Int)Int

scala> foo(3, double)
res1: Int = 6

In addition, note that with method, you get a new function on every call.

scala> def double: Int => Int = _ * 2
double: Int => Int

scala> double eq double
res15: Boolean = false      //false because every time double refers to new instance and hence is not equal unlike val. 

Now, lets go to closure. Both function literal defined with val and def method return function value (object). The function value (the object) that’s created at runtime from function literal is closure. On the other hand, a method is not a closure, but the function value you get from calling a method is a closure.

scala> var more = 1
more: Int = 1

scala> val foo = (x:Int) => x + more    // foo is clouser.
foo: Int => Int = <function1>

scala> def bar(x:Int):Int = x + more    // bar is not clouser.
bar: (x: Int)Int

scala> val barClouser : (Int => Int) = bar  // barClouser is clouser. 
barClouser: Int => Int = <function1>

scala> val barValue = bar(3)    // bar is converted to clouser and then clouser value is evaluated and result is assigned to barValue variable. 
barValue: Int = 4   

scala> val fooValue = foo(3)    //foo value is evaluated and returned as value which is assigned to fooValue variable. 
fooValue: Int = 4

Upvotes: 2

Related Questions