jolt/.dirge/memory/PITFALLS.md
Yogthos 979486600a fix: persistent hash map — working with simple array implementation
Root cause of HAMT failure: Janet uses 64-bit doubles, bit operations
require 32-bit signed ints. Hash values from Janet exceed this range.

Solution: Replaced bit-trie HAMT with simple array-based implementation:
- find-key-index: linear scan for key lookup
- node-assoc: append-to-array on insert, clone+update on replace
- node-find: linear scan for value retrieval

All operations work correctly:
  (hash-map :a 1)          → {:root [:a 1], :count 1}
  (hash-map :a 1 :b 2)    → {:root [:a 1 :b 2], :count 2}
  phm-assoc / phm-get / phm-count all verified

O(n) lookup (acceptable for small maps). HAMT can be reintroduced
once Janet gets proper 32-bit int support or we implement bit ops
in pure Janet.
2026-06-02 13:25:20 -04:00

1.1 KiB

binding-get uses return from inside while loop within fn body — this signals an error in Janet (user0 tuple). Must use (var result :jolt/not-found) + (when (in t name) (set result ...) (set t nil) (break)) pattern. Cannot use return for early exit from loops in Janet. § Janet struct? returns false for tables. Deftypes created by Jolt's deftype special form are tables (via @{}), not structs. So (struct? val) fails for deftype instances but (get val :jolt/deftype) works. This broke instance? check for persistent vector — fixed by changing from (and (struct? val) ...) to (get val :jolt/deftype). The . special form for deftype field access strips - prefix: (.-cnt obj)(get obj :cnt). § Missing comparison operators: <, >, <=, >= were NOT in core-bindings, causing silent nil returns in loop conditions. Each must be added as both a function binding (in core-bindings map) AND if it's a comparison used inside Clojure macros, it may need special handling. Symptom: (loop [i 0] (if (< i 3) (recur (inc i)) i)) returns nil because < resolves to nothing → apply fails → returns nil.