Will's Research Blog

miniKanren and declarative programming and stuff. And ponies.

Closures and Mutable State

John Carmack recently tweeted:

I’m still waiting for the insight that makes closures usefully cool instead of a scary way to hide mutable state. Any great examples?

and

I have no issue at all with capturing immutable state, and I don’t have enough experience to decry arbitrary capture, but it gives me pause.

John asks an interesting question, so I decided to collect answers that won’t fit in 140 characters. If you send me your favorite example of using mutable state within closures, I’ll add it to this post.

The canonical example of using mutable state with closures is to encode object-oriented programming within a functional language. For example, Dan Friedman’s paper on Object-Oriented Style uses mutable state, closures, and syntax-rules hygienic pattern-matching macros to add a simple object system to Scheme.

Kent Dybvig (formerly of Indiana University, now at Cisco) gives several examples of mutable state and closures in The Scheme Programming Language, 4th ed including memoization, multitasking with engines (“a high-level process abstraction supporting timed preemption”), and—of course—an object system.

The first submitted answer is from my friend and co-worker Andy Keep. I’ve taken the liberty of adding appropriate hyperlinks, for context.

Consider a simple counter:

1
2
3
4
5
6
7
8
9
10
11
(define next-count
  (let ((count 0))
    (lambda ()
      (let ((nc count))
        (set! count (+ count 1))
        nc))))

(next-count) ;=> 0
(next-count) ;=> 1
(next-count) ;=> 2
(next-count) ;=> 3

Here, the closure will contain the count variable, which is mutable (though one way to deal with this is closure conversion, which is what we do in the [Indiana University P423] class compiler and Chez [Scheme]).

In general any time you have some local-state that can be changed amongst a set of functions internally you are going to have mutable state in a closure. (In fact, there is almost no point of using a mutable variable if it isn’t going to be captured in a closure, because in that case it can almost always be modeled by simply rebinding and shadowing.)

Just to be clear the closures themselves are never mutated, they just contain a pointer to data structure (in our case a pair) that gets mutated. This is as opposed to languages like Ruby, where it is actually possible to mutate the closure.

In both cases this is an implementation detail, but it is an one to note, because in Ruby it can lead to mutation that is not statically determinable, where as in Chez the only fields that can be altered are those that set! was called on somewhere in the program.