Liking cljdoc? Tell your friends :D

Symbolic Keywords

In many clojure libraries, the behavior of complex functions may be controlled by a map. For example:

(:require [brewtility.units :as units])
(units/display :volume 1.5 :liter) ;; => "1.5 l"
(units/display :volume 1.5 :liter {:suffix :full}) ;; => "1.5 liter"

This allows us to easily extend the definition of a single function to fulfill multiple complex needs; however, option maps come with considerable drawbacks. When a map is keyed with keywords, it is easy to introduce subtle, hard-to-detect errors. Since most of these functions select default values for keys not present, typos can lead to meaningful differences in behavior. For example:

(:require [brewtility.units :as units])
(units/display :volume 1.5 :liter) ;; => "1.5 l"

;; Not the missing "f" in the key :sufix
(units/display :volume 1.5 :liter {:sufix :full}) ;; => "1.5 l"

Because keywords aren't picked up by the auto-complete features of most editors, they're vulnerable to all classes of transpositional errors. Further, the options themselves are unable to carry metadata and documentation with them, making them little more than magic values.

For this reason, it is helpful for libraries to include symbols which point to the "magic" keywords used in option maps. This has several benefits:

  • Misspelled or incorrect option keys are compile-time errors, instead of runtime bugs
  • Symbols can carry metadata like documentation, deprecation notices, and point to alternative options
  • Context-aware editors can auto-complete options

Here's can example:

(:require [brewtility.units :as units]
          [brewtility.units.options :as options])

(units/display options/volume 1.5 options/liter) ;; => "1.5 l"
(units/display options/volume 1.5 options/liter {options/suffix options/full}) ;; => "1.5 liter"

Most option maps in brewtility support symbolic keywords. These keywords are available in the namespaces ending in .options. These files live as close to the code relying on them as possible; for example, the options for all unit conversion operations (e.g. brewtility.units, brewtility.units.time, brewtility.units.color, etc.) are available in brewtility.units.options.

Further, the option keywords are preferred for library development. A single source of truth for the name of a common option, such as precision, limits the possibility of incorrectly retrieving the values used by that option.

Can you improve this documentation?Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close