Varun Paprunia
Varun Paprunia

Reputation: 33

Returning code block in Scala

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

Answers (2)

pedrofurla
pedrofurla

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

som-snytt
som-snytt

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

Related Questions