The Non-Functioning Programmer (Part 2) – Affairs of State


At Caplin we are always encouraged to use some of our time investigating new technologies and so last month I started to write about some of the things I have learnt while working with functional languages. One of the things which I have found most interesting about functional languages when I first started to use them is their approach to state. Functional languages do not, generally, have mutable state. This means that once a “variable” has been set, it cannot be changed. So how does one create a interactive applications without mutable state?

Let us consider a simple inventory app, one written in an imperative style in Java and one written in a functional style in Clojure.

In Java we may make an inventory class which looks a little bit like this:

import java.util.HashSet;

public class Inventory {
private final HashSet inventory= new HashSet();

public void pickupItem(Item item) {
inventory.add(item);
}

public void dropItem(Item item) {
inventory.remove(item);
}

public int getNumberOfItemsInBag() {
return inventory.size();
}

public boolean isItemInBag(Item item) {
return inventory.contains(item);
}
}

This is a very simple class. It simply has a set of items which can have items added or removed. When an item is added or removed then the Set is updated, so that it now contains one more item or one lesss item. It is still the same object, but now it contains different items.

Obviously this is not possible with functional languages. In Clojure we have to do things a little differently.


(def inventory #{})

(defn pickup-item [item]
(def inventory (conj inventory item))
)

(defn drop-item [item]
(def inventory (disj inventory item))
)

(defn get-number-of-items-in-bag []
(count inventory)
)

(defn is-item-in-bag? [item]
(contains? inventory item)
)

In functional languages, if the same function is called with the same arguments you will always get the same value. So we need some form of state to save things to an inventory. But how can we do this if variables are immutable and therefore can’t change?

Clojure allows us to have a mutable reference to an immutable variable. In this code you can see us creating a brand new variable with (conj inventory item), and then using def to dynamically rebind “inventory” to this new object. In this way our variables are immutable, but we can have state.

While the difference between altering a variable and rebinding a reference to new variable may seem a subtle one, it is vitally important as I will come onto when we get into multi-threading.

Also, please be aware, that this particular use of the “def” function, will isolate the variable on a per thread basis, so if another thread were to try and access this variable, they will not see any of the changes which the other thread has made. I will be covering this further in my future blog on multi-threading.

Related Posts with Thumbnails

There are no comments yet, add one below.

Leave a Comment