I started learning Elixir a week ago. Although this has been at the top of my To-do list for quite a while, I couldn’t take it up due to other commitments.
I love Elixir. It is a great functional programming language. Having programmed in Lisp for a long time, I immediately noticed the similarity between Lisp and Elxir, especially in the area of Macros. More on this in a future article…
The first thing I decided to check was whether Elixir supports function “closure”, where a function carries state with it. Today’s article is an attempt to explore this idea.
Take a look at the following Lisp function:
The function “counter” takes two arguments, an initial value and a delta to be applied every time. It sets up a local environment, where the variable “cur” is initialized with the passed initial value. It then defines and returns an anonymous function that increments the local state with “delta”, each time it is called.
The following shows how it is used:
In the first step, we call “counter” passing 10 as the initial value and 3 as the delta. This returns an anonymous function, which we store in “incr”. Subsequently we call the anonymous function and it correctly returns the current value based on the previous state and “delta”. We then obtain another anonymous function, this time based on initial value of 100 and delta of -2. As you can see, the next few steps confirm that this too works as expected.
What this shows is that the anonymous function carries with it the environment in which it was created.
Let us mimic this approach in Elixir. Here is our first attempt:
We run this code in “iex”, the interactive shell for Elixir. Take a look at the output:
First, we compile and load the file into the shell. We get an un-used variable warning, and this itself is a clue that something is not as expected!
We create a counter object (an anonymous function), passing 10 as the initial value and 5 as the delta. When we call this function repeatedly, we see that it returns the same value each time. This is because the local variable “cur” is passed by value to our anonymous function and hence is not updated when it is modified within the function – in contrast to Lisp.
Since “closure” is not directly supported in Elixir, is there a way to implement the counter abstraction such that it works as in the Lisp example?
ETS or Elixir Term Storage comes to our rescue. This is a costly approach, but we are not concerned about that here. Here is the code that uses this feature:
Here we create a “named” ETS table for storing the current value and the delta. The anonymous function uses this table to keep track of the current counter value and update it when it is invoked.
Here is the output with this change:
Good! This works as expected. By the way, the “reset” function is required. It deletes the ETS table so that it can be garbage collected by the VM.
Coming to the main point of this article, Lisp supports closure, whereas Elixir does not. But there are many ways in Elixir – including the one using ETS – that enable state-based programming.
I hope to spend more time understanding Elixir in the weeks to come, so stay tuned for more such articles!
Download the code from here.
Have a nice weekend!
Recent Comments