Reputation: 33
I was trying to implement the closure example in Scala, from Neal Ford's Functional Thinking presentation which is in Groovy. Refer slide # 43 & 44 https://sea.ucar.edu/sites/default/files/Functional_Thinking.pdf
def makeCounter : Unit = {
var localVar = 0
return { localVar += 1 }
}
This code returns an anonymous function. Now I want to increment the localVar by invoking this anonymous function.
I have two questions:
1. How do I invoke the anonymous function?
2. After invoking it how do I check if the value of localVar is incremented or not?
First I tried this -
val c1 = makeCounter(). It threw below error:
error: makeCounter of type Unit does not take parameters
Then I tried this.
val c1 = makeCounter
This didn't give any error. Only printed c1: Unit = ().
Then,
print(c1) printed (), whereas c1() gave the same error.
Upvotes: 0
Views: 1191
Reputation: 12783
First of all. Don't use return
, its semantics is completely different in Scala than in Java or Groovy.
The Unit
type isn't a synonym for anonymous function. It's more like a indication of side-effects.
The type for an anonymous function is () => A
. In your case you want a function that doesn't return any thing, but causes a side-effect. So its type should be () => Unit
.
Let's see some code:
def makeCounter : () => Unit = {
var x = 0
{ () => x = x + 1 }
}
val counter = makeCounter
counter(); counter(); counter()
Great! We made makeCounter give us a fresh counter!
There is only one problem. x
is a local variable in the method makeCounter
and since it's never returned we can't see its value! Ever! We could, for example, remove x
from the method, making it public in the outer scope. But it's not very functional. Instead let's make the function return it:
def makeCounter : () => Int = { // Notice now, instead of Unit we use Int
var x = 0
{ () => x = x + 1; x }
}
val counter = makeCounter
println(counter(), counter(), counter())
val counter2 = makeCounter
println(counter2(), counter2(), counter2())
You will see "1,2,3" twice. Once for each counter.
Upvotes: 6
Reputation: 39577
I didn't look at the presentation, so I don't know if this is functional thinking or just one of the slides on the road to functional thinking, but:
scala> def f: () => Int = {
| var v = 0
| () => v += 1 ; v }
f: () => Int
scala> val g = f
g: () => Int = <function0>
scala> g()
res0: Int = 1
scala> g()
res1: Int = 2
scala> g()
res2: Int = 3
The function literal returned by f
is, of course, everything after the parens.
Upvotes: 1