10.1 Features of FSet

One thing I’ve tried to do in FSet is to choose names for functional update operations carefully. I recall reading once about newcomers to Java trying to use its BigInteger class, which is functional. They tended to expect an expression x.add(y) to mutate x to contain the sum, when it returns the sum instead. I contend that naming the operation plus instead of add would have largely prevented this confusion; people have written x + y since they were children in school, and no one thinks of that as somehow changing the value of x, whatever that would even mean in a mathematical context. (Java doesn’t support operator overloading, so literally making x + y work on BigInteger was not an available option; x.plus(y) is the closest one could get.)

Two important operations in FSet are named with and less; with adds an element or pair to a collection, while less removes one. These names come from SETL. Like plus, they are prepositions.

Naming things is always a matter of tradeoffs. Good names make code understandable by carrying the right connotations, but names also need to be reasonably familiar words, and for common operations, not too long. I wouldn’t go so far as to say that all functional update operations should be named by prepositions, but I do think that, other things being equal, prepositions and nouns tend to be better choices than verbs, and verbs that don’t connote mutation are better than those that do. In a couple of cases, where the obvious names insert and splice strongly connote mutation, I have used their past participles (inserted and spliced) instead of their base forms. (Honesty compels me to admit that this is a recent change; I have not, historically, adhered to my own desideratum as well as I would have liked. But I still recommend it.)

Here are some other functional collections libraries and the names they use for operations like with and less:

Librarywith (on sets/on maps)less (on sets/on maps)notes
Clojure coreconj / assocdisj / dissoc
Rackethash-sethash-remove1
Scalaincl / updatedexcl / removed2
Haskellinsertdelete3
SML/NJadd / insertsubtract / remove
Pyrsistent (Python)add / setremove
RPDS (Rust)insertremove

Notes:

  1. Only maps (hash tables) are provided. Racket uses the popular Scheme convention that names of mutating operations end in !; someone familiar with that convention should be able to guess that these are functional updates.
  2. Here we see a use of past participles.
  3. Of course, there’s no ambiguity here since anyone writing Haskell knows it’s a pure functional language.

A lot of these sound to me like verbs of mutation, with Clojure and Scala being the two languages that seem to have gone to some effort to avoid those.

Another area where I would hold FSet up as an example is space efficiency. I wanted to support client programs that use many small collection instances, as well as those that use large collections. Two things I have done to reduce space overhead are:

Turning to semantic features, FSet has several that I would recommend to language and library designers: