Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Functional style counter in Groovy

I am very new to functional programming concepts and was watching a presentation by Neil Ford in youtube. There he talks about a counter to demonstrate a piece of code without using a global state(at 20:04). Coming from Java world, I have some difficulty to understand the concept here and how the counter is incremented. Below is the relevant code

def makeCounter() {
    def very_local_variable = 0;
    return {very_local_variable += 1}
}

c1 = makeCounter()
c1()
c1()
c1()

c2 = makeCounter()
println "C1 = ${c1()}, C2 = ${c2()}"

He goes on to say that C1 = 4, and C2 = 1 will be printed. How does this happen? I am sure my lack of understanding here stems from probably a conceptual failure in how Groovy works or probably there is something general in functional languages like Groovy, Scala etc. Does a local variable within a method maintains its state until the function is called again and assigned to another variable? (A google search with "functional counter groovy| scala" brings nothing)

like image 503
senseiwu Avatar asked Dec 18 '13 19:12

senseiwu


1 Answers

I don't know why this question doesn't have an answer, but it probably deserves at least one for future visitors.

What you have written above is a simple example of closure. Closures are a language-agnostic idea, not tied to Groovy at all. You use them all the time e.g. in JavaScript.

A closure is essentially a function or reference to a function together with a referencing environment.

In your example each call to makeCounter introduces a new local very_local_variable, it's clear I think. What you do in the second line of that function is return a closure ({ .. } syntax) that takes no arguments and returns the local variable incremented by 1. The closure has access to that variable as long, as it exists (it's part of the referencing environment).

Each call to makeCounter creates a new local variable and returns a new closure, so each of them operates on its own local variable / environment.

Actually, if you come from Java island it shouldn't be that new to you. You have anonymous classes, which can access final variables, e.g.

Runnable makeCounter() {
  final int[] very_local_variable = {0};
  return new Runnable() {
      @Override
      public void run() {
          very_local_variable[0] += 1;
      }
  };
}


Runnable c1 = makeCounter();

c1.run();
c1.run();
c1.run();

Declaring the local variable as array, returning it as Runnable functor and so on.. it all comes from Java's design and limits, but in essence it's really close to your code. Java 8 bridges the gap even closer:

Runnable makeCounter() {
    int[] very_local_var = {0};
    return () -> { very_local_variable[0] += 1; };
}
like image 64
emesx Avatar answered Sep 16 '22 20:09

emesx