Reputation: 327
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
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