0

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.

2 Answers2

6

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.

pedrofurla
  • 12,763
  • 1
  • 38
  • 49
  • Sorry, I only read as far as `should be ()=>Unit` when I posted my version. Maybe you could remove the extra semi and braces from the final answer. "Is that your final answer?" – som-snytt Sep 08 '13 at 03:04
  • 1
    @som-snytt Actually, I have problems visually parsing your version. I didn't even know you could arrange things like that. – pedrofurla Sep 08 '13 at 04:15
  • @pedrofurla If I don't use return it gives an error - "error: block must end in result expression, not in definition". So I returned it. But still println(counter()) doesn't print anything – Varun Paprunia Sep 08 '13 at 05:44
  • I wouldn't normally put it on a single line except for typing it in the REPL. But compare http://stackoverflow.com/a/18159362/1296806 and more explanation at http://stackoverflow.com/a/13873899/1296806. – som-snytt Sep 09 '13 at 03:47
  • What puzzled be was the `;`. So, shall it be `(() => v += 1) ; v` returning v? Or shall it be ``(() => v += 1 ; v)`, return a function that returns v? If I didn't test I'd still be thinking the former is what happens. – pedrofurla Sep 09 '13 at 06:50
  • I see what you mean. I wear special bi-focal lenses just for this syntax. For the record, I didn't see your comment because of no at. I don't know why SO thinks I'm not interested in a stream of commentary to which I have contributed. Or OK, "contributed". I guess SO would say, This is not a chat room. So 1990s. – som-snytt Sep 11 '13 at 05:21
1

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.

som-snytt
  • 39,429
  • 2
  • 47
  • 129
  • This works fine. But I have a conceptual doubt here. As I understand, this function definition with def f: () => Int implies that it will not take any parameters and return an Int. But isn't that wrong because this function is returning an anonymous function and not an Int? Or am I missing anything here? – Varun Paprunia Sep 08 '13 at 17:25
  • @VarunPaprunia Method `f` is parameterless. See how it's invoked on line 2 without parens. It returns a `() => Int`. Value `g` is applied using `g.apply()` or `g.apply` (with parens automatically added) or `g()` (as call to `apply`). – som-snytt Sep 09 '13 at 03:53