How to implement a counter in functional programming way

Manu Chadha picture Manu Chadha · Nov 30, 2016 · Viewed 7.6k times · Source

While trying to understand companion objects, I have written following code which counts the number of times a class was instantiated. I had to use a 'var' to keep the count. Is there a 'functional programming' way to achieve the same task i.e. use immutable variables.

class C {
  C.counter+=1
  def someCFunction = {println ("some C function. Counter is "+C.counter)}
}

object C{
  var counter:Int=0 //I do not want to use var
}

val c1 = new C
c1.someCFunction

val c2 = new C
c2.someCFunction

Answer

hugomg picture hugomg · Nov 30, 2016

One of the big properties of a purely functional program that avoids mutable variables and other side effects is that the value that an expression evaluates to depends only on the expression itself. It does not depend on what order things are evaluated (left to right, right to left, strict, lazy), the state of the operating system, time of day, etc.

In particular, this means that in a purely functional setting every call to new C will return a completely identical counter object. This is usually a good thing because it makes it easier to reason about your program but it kind of gets in the way of what you are trying to do there. To make the C objects be different you would need to explicitly pass their counter values, which to be honest, is just sweeping the problem under the rug.

val c1 = new C(0)
val c2 = new C(1)

If you want to have a global "counter" variable like the internal class variable you were using one possible way to implement it in a purely functional setting would be to pass the counter value to every function that needs a counter and have those functions also return the updated version of the counter. For a brief example:

def increment_counter(n: Int): Int = { n + 1)

def create_c(n: Int): (C, Int) = {
    val c = new C(n)
    val n' = increment_counter n
    (c, n')
}

val n = 0
val (c1, n') = create_c(n)
val (c2, n'') = create_c(n')
val n' = increment_counter(n)

You can structure this a bit better with a State Monad pattern (most introductions to monads probably will have this as an example).

However, it is very possible that it will end up more complicated than just using a mutable variable for the counter instead. In fact, I normally use mutable variables for these "globally incrementing counters" in the functional languages that allow me to do so.