Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Values API reference (0.2 alpha)

Practical API for Dacite values as implemented in the Clojure / SCI reference library. For how to use values, start at The Dacite way and the cookbook. Internals: Values.

Public namespace: dacite.value (pair with dacite.store for stores).

What is a Dacite value?

A value is store-aware and content-addressed:

PropertyAccess
Content hash(v/hash v)
Owning store(v/dacite-store v)
Type name(v/type v)
Host content(v/realize v) — explicit, never implicit deref

Values are immutable. Updates return new values that share unchanged nodes with the old ones. Laziness is natural: you only need the nodes you access.

(require '[dacite.value :as v]
         '[dacite.store :as s])

Constructors

Every constructor takes a context first: a rooted store, a v/root, or another Dacite value. New nodes go into that store.

FormRole
(v/vector ctx & xs)Vector
(v/map ctx & kvs)Map
(v/set ctx & xs)Set
(v/string ctx s) / (v/blob ctx bs)Sequences
(v/i64 ctx n) (and other scalars)Typed scalars
(defn add-todo [todos title]
  (v/conj todos (v/map todos "title" title "done" false)))

(v/vector rs 1 2 3)
(v/i64 rs 42)

Root (value-level)

The store layer keeps a mutable hash. Wrap it once:

(def r (v/root (s/mem)))

(v/cas! r nil (v/vector r))
(v/swap! r v/conj (v/i64 r 1))
(v/deref r)   ; => current Dacite value or nil

On the JVM, the root also implements atom interfaces (@r, swap!). There is no portable unconditional reset — seed with cas! from nil.

FunctionRole
rootWrap a rooted store
derefCurrent value or nil
swap!CAS-retry apply
swap-info!Same, plus {:value new :retries n}
cas!Compare-and-set (seed from nil)
add-watch / remove-watchWatch value transitions

Collection API

First argument is always a Dacite value:

FunctionRole
dacite-value?Predicate
typeType name string
realizeHost content
hashContent hash
get-valueRehydrate hash from store → value ([st h])
countElement/entry count, O(1)
empty?Zero elements?
seqElements or map entries as wrapped values
nthIndex into vector/string/blob
getMap key, set membership, or vector index
contains?Presence of key/index
assocVector index or map key → new value
dissocRemove map key
conjAppend / add entry
peek / popVector end
remove-nthVector without index
slice[start, end) of a vector, string, or blob (same type; shared leaves; O(k log n))
keys / valsMap keys or values as wrapped sequences
nativeHost atom for a scalar, or host String for a Dacite string. Collections throw. Optional char limit (or *string-char-limit*) realizes at most that prefix, then throws if the string is longer.
as-bytesHost bytes for a blob. Optional limit; missing nodes throw :dacite/missing.
pr-strBounded debug render. Never throws. Long strings: "prefix…" (n chars).
get-in / assoc-inNested path lookup / update (creates intermediate maps)
update / update-inApply a fn at a key or path; result is assoc’d back

Example:

(let [st (s/mem)
      vec (v/vector st 10 20 30)
      v2  (v/conj vec 40)]
  [(v/count vec) (v/count v2)
   (v/realize (v/nth v2 3))])
;; => [3 4 40]

Identity and hashing

  • Two values with the same type and content have the same hash on every host (see bin/hash-parity.sh).
  • Print / log hashes with (s/hash->hex h) and parse with (s/hex->hash s).

Not part of the public value API

AreaNotes
Finger-tree / HAMT node typesInternal store entries
Wire codecsdacite.wire / dacite.wire.binary
dacite.value.types / .scalar / .collectionsImplementation
dacite.convertJVM test hatch (dac->clj / clj->dac), not app code