archives

Clojure's Approach to Identity and State

Clojure has been discussed here before. It fits in the Lisp family with S-expressions, macros, and functions as values. Like most Lisps, it's dynamically typed and impure. But its target focus is concurrency so symbols are defined immutably by default; its standard library's collection structures are immutable and persistent; and its various mutable concepts are threadsafe except, of course, for the back doors implied by I/O and JVM library interoperability. See vars, refs, and agents.

What I wanted to highlight is position paper of sorts that Rich Hickey has posted on Clojure's Approach to Identity and State. An excerpt:

While some programs are merely large functions, e.g. compilers or theorem provers, many others are not - they are more like working models, and as such need to support what I'll refer to in this discussion as identity. By identity I mean a stable logical entity associated with a series of different values over time. Models need identity for the same reasons humans need identity - to represent the world.
...
In Clojure's model, value calculation is purely functional. Values never change. New values are functions of old, not mutations. But logical identity is well supported, via atomic references to values (Refs and Agents). Changes to references are controlled/coordinated by the system - i.e. cooperation is not optional and not manual.

Hickey also addresses the choice to not follow Erlang's model.

There are other ways to model identity and state, one of the more popular of which is the message-passing actor model, best exemplified by the quite impressive Erlang. ... It is important to understand that the actor model was designed to address the problems of distributed programs. And the problems of distributed programs are much harder ... Clojure may eventually support the actor model for distributed programming, paying the price only when distribution is required, but I think it is quite cumbersome for same-process programming. YMMV of course.

The essay is worth a read on a couple of levels of interest to LtU. At an abstract level, it's a good example of a well-articulated design justification. Agree or not, it's clear that Hickey gave thought to his decisions. Too many language designers fall into the trap of blindly inheriting semantics from a favorite language and end up putting new lipstick on the same pig. Any language designer would do well to write an essay or two like this before jumping into their venture.

At the specific level, the core approach is certainly worthy of discussion and alternative designs. Is mutable state really the best way to deal with "working models"? Are there things that the pure functional camp can do to make "working models" more convenient, e.g. do Clean's uniqueness types fit the bill at least for sequential programming, or are they too restrictive? Are there things that can make Erlang style actors less cumbersome to use especially when distribution isn't necessary?

Sound and Complete Type Inference in BitC

Just a "head's up" that the extended version of the mentioned paper is now available on the BitC docs page. Given the amount of type algebra, it doesn't do very well in HTML. The PDF version is SRL2008-02. This is an extended version of our upcoming APLAS paper that includes all of the supporting proofs. So far as we know, this is the first sound and complete, integrative treatment of polymorphism and mutability in a single inference scheme.

Subsequent to this work, the BitC type system was revised to add a const meta-constructor and to re-specify mutability on a path-wise basis. This corrects a problem with deep immutability that was revealed by by-reference parameters and inner references. The revised type rules can be found in SRL2008-03. The revised rules remain sound and complete, and should be implemented in the compiler by some time early next week.

Still to come before we can release the first compiler are existential types, effect types, and structure subtyping.

I don't want to pick on Clojure (which looks very cool), but in light of the current discussion about state in Clojure, it may be appropriate to offer a counter-position:

Claim: If it isn't possible to efficiently self-host the runtime of your favorite functional language, then you can't argue credibly against imperative programming yet. At most, you might sustain an argument that imperative programming can (and perhaps should) be relegated to a very restricted part of your runtime library. This argument, in our view, evaporates in a puff of logic when performance criteria are admitted into the language evaluation.

In BitC, we take the position that pure programming is good when you can afford it (which is most places), but that there are places where we don't yet have any realistic alternative to imperative programming idioms.