Dunaj provides an alternative core API for the Clojure. Its main aim is to experimentally test major additions to the language. Dunaj deals with language features that require changes across different parts of Clojure and which cannot be evaluated in isolation.

Dunaj is not an academic endeavour. It is focused on being practical and a significant effort was made to provide implementation that is backwards compatible with Clojure. Dunaj code integrates well with existing Clojure libraries and tools. Dunaj’s main goal is to bring Clojure even more towards simplicity, consistency and performance. See design and rationale for more information about Dunaj’s design and motivations.

Dunaj Experiments

Dunaj focuses on number of experiments, which are described in more detail in a separate crash course for Clojure developers. List of Dunaj experiments with brief description follows:

  Deconstructed API

  • Core functionalities split into several namespaces

  • API 'presets' that automatically refer commonly used vars

  • Bootstrapping and low level stuff no longer part of a public API

  Type signatures

  • Signatures independent from type checking or validation tools

  • Type aware syntax for def-like macros, let, loop and fn

  • Automatic generation of host type hints

  Protocols first

  • Using protocols and deftypes instead of host interfaces and classes

  • Separate SPI and helper functions for custom language extensions

  • Protocol factories for explicit extensions of abstract data types

  Simplified API

  • Core functions work on top of protocols, not concrete types

  • Fully qualified special symbols

  • Consistent conventions for names

  Reducers first

  • Collection functions return collection recipes instead of lazy seqs

  • A continuation for reductions

  • Multireducibles, foldable transducers

  Host Performance

  • More primitive types for function arguments and return values

  • Dedicated namespace for working with host primitive integers

  • Low level data containers for bulk data processing

  Data Formatters

  • Parsers with transducer support and optional lazy parsing

  • Printers with transducer support and pretty printing

  • Built-in formatters for UTF-8, JSON, EDN/CLJ and more

  Resources

  • Reducible blocking and non-blocking I/O, network resources

  • Scopes, a GC for resources

  • Systems, a concept for managing the lifecycle of resources

  Improved Math

  • Facilities for rounding, with both decimal and significant digits precision

  • Reducible secure random number generators with transducer support

  • Math functions of an angle, exponentiations and logarithms

  Documentation

  • User friendly and comprehensive documentation

  • Dedicated metadata keys for IDEs

  • Facilities for generating documentation

Dunaj Specification

See specification page for a description of Dunaj’s concepts, types, facilities and conventions.

API

API provided by Dunaj is designed as an alternative to clojure.core API. See Dunaj API page for list of all namespaces and their vars. By design, Dunaj API is more user-centric, omiting bootstrapping and low level stuff. Functionalities are divided into separate namespaces, which prevents name clashes.

Having core vars in separate namespaces may worsen the tedious task of requiring multiple namespaces for handling basic stuff (instead of just requiring one clojure.core). To make this more bearable, Dunaj API preset automatically refers most commonly used vars. See dunaj.core for list of automatically referred vars.

API presets functionality is not available in Dunaj lite.
An additional preset called bare is provided that does not refer to any var or host classes. Use this preset if complete control of what is referred in the namespace is needed.
1
2
3
4
5
6
;; classic Clojure API
(ns foo.bar)

(time (reduce + (take 100000 (range))))
;; Elapsed time: 42.034772 msecs (Clojure 1.7 alpha5)
;;=> 4999950000
1
2
3
4
5
6
7
;; new Dunaj API
(ns foo.bar
  (:api dunaj))

(time (reduce + (take 100000 (range))))
;; Elapsed time: 15.84147 msecs
;;=> 4999950000
1
2
3
4
5
6
7
8
9
;; Bare API, no symbols refered, not even host classes
(ns foo.bar
  (:api bare))

(+ 1 2)
;; java.lang.RuntimeException: Unable to resolve symbol: + in this context

String
;; java.lang.RuntimeException: Unable to resolve symbol: String in this context

Extending Dunaj

In Dunaj, a significant effort was put into providing an extensible API, so that users can create new types of collections, resources, formatters, etc. Such user created types work seamlessly with most functions defined in Dunaj API. This has been achieved by defining more than a hundred public protocols that are used to define virtually every extensible functionality in Dunaj. Moreover, helper functions are available for tasks that often occur when implementing custom types or functionalities.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
(ns foo.bar
  (:api dunaj)
  (:require [dunaj.coll :refer [ISectionable ICounted]]
            [dunaj.concurrent.forkjoin :refer [IFoldable]]
            [dunaj.coll.helper :refer [advance-fn fold-sectionable prepare-ordered-section]]))

(deftype FiniteRepeat
  [n :- Integer, val :- Any]
  IRed
  (-reduce [this reducef init]
    (let [af (advance-fn [ret i]
               (zero? i) ret
               :else (recur (reducef ret val) (dec i)))]
      (af init n)))
  IFoldable
  (-fold [this reduce-fn pool n combinef reducef]
    (fold-sectionable this reduce-fn pool n combinef reducef))
  ICounted
  (-count [this] n)
  ISectionable
  (-section [this nb ne]
    (let [l (count this)
          ne (prepare-ordered-section nb ne l)]
      (if (and (zero? nb) (== ne l))
        this
        (->FiniteRepeat (- ne nb) val)))))

(defn finite-repeat :- IRed
  "Returns a collection of vals of length n."
  [n :- Integer, val :- Any]
  (->FiniteRepeat n val))

Those same protocols and helper functions are used in Dunaj’s built-in types, so that custom types can be seamlesly integrated into Dunaj. Protocols and their respective methods are described in separate Dunaj SPI part of the documentation. In addition, Dunaj API provides helper functions in following namespaces: