Dunaj - Deconstructing Core API

While Clojure provides its functionalities in multiple namespaces
(e.g. clojure.string, clojure.zip), the majority of it
is defined in a single namespace called clojure.core.
The first Dunaj experiment explores the idea of having multiple
small namespaces where functions, macros and other public vars
are grouped by their purpose. It investigates whether such separation
is possible at all and whether it can be practical and useful.
It will be interesting to see whether this experiment will be also
able to lower the learning curve for beginners and improve the ease
of use and clarity of the Clojure API.

Background

Clojure follows a single namespace design with exceptions for
functionalities with an obvious special purpose and those specific
to a given host (e.g. clojure.test, clojure.java.io).
Implementation driven and historical reasons dissuade from separating
many other special purpose or host specific functionalities.
This design decision manifests itself in various ways:

Low level and internal functions (such as monitor-exit, →VecSeq
or proxy-mappings) are part of a public API together with widely
used functions such as map, let or defn.

In some cases, name clashes are solved by clever prefixes and
suffixes (bit-and, ns-aliases, +'), while for others
a special namespace is used
(clojure.core.reducers/map, clojure.edn/read).

Special purpose functions (e.g. for the unchecked math or for
bitwise logical operations) are mixed with ordinary ones.

Host specific stuff is mixed in a single namespace with things
portable across hosts.

Some specialized functionalities are isolated in a separate
namespace (e.g. clojure.walk, clojure.zip), while others are not
(e.g. namespace related ns-* vars, array creation and coercions).

Current core API is non-trivial to document, port across hosts and may
lead to unnecessary confusions. Implementation details of a
bootstrapping process and historical reasons currently dictate, to an
extent, the shape and contents of the API intended for everyday use
by application or library developers.

Define a concept of API presets that control which
functions, macros and vars gets referred by default.

Let user choose which API preset he/she wants to use in his/hers
namespace, using classic clojure.core as a default.

The upside of this approach is that backwards compatibility is
maintained and users can freely intermix multiple APIs in their
projects. Functionalities can be more logically separated by their
purpose. List of automatically referred vars is no longer driven
by the namespace in which vars were defined, but this list is handled
by a separate API preset that can be extended and customized.

Dunaj API and SPI

Dunaj takes functionalities found in clojure.core and in 9
other clojure namespaces (such as clojure.string and
clojure.walk) and divide them into more than 50 namespaces,
grouping vars by their purpose. Moreover, distinction between
API (functions, macros) and SPI (protocols,
protocol methods) has been made explicit in the documentation that
comes with Dunaj.

API Presets

API presets enable developers to elegantly switch between Dunaj and
Clojure within the same project. ns macro in Clojure has been
patched to support an additional :api declaration that states which
API preset should be used in the respective namespace. Dunaj provides
three built-in API presets:

clojure - Refers all vars from clojure.core, plus Clojure’s
special symbols and a default set of host classes. This preset is
used by default when no preset is specified in the ns declaration.

bare - Does not refer any vars or host classes. Refers special
symbols.

dunaj - Loads Dunaj and refers less than 600
most commonly used vars from Dunaj
(out of more than 1700). Refers special symbols too.
No vars from clojure.core are included.

API Presets functionality is not available in Dunaj lite.
Please consult Dunaj lite documentation for
a way how to work around this limitation.

Custom API presets can be easily created and used in the same way as
the three built-in presets. Following examples shows how API presets
are used.