- Reader: maps, sets, syntax-quote, dispatch macros, metadata - Runtime: CljVal type system, 80+ core functions (collections, strings, math, IO) - Emitter: full CljVal-based code generation, macro expansion, inline fns - Macros: defmacro with compile-time evaluator, ->, ->>, and, or, when, cond, for, doseq - Nim Interop: nim/module/function syntax, auto-import, type mapping - CLI: cljnim -e '<code>' for quick evaluation - Tests: 60 unit tests (reader + emitter) - Benchmarks: AOT suite showing 543x startup, 679x factorial vs JVM Clojure - CI: GitLab CI pipeline - Runtime library: lib/cljnim_runtime.nim (1070+ lines)
14 KiB
Пътна Карта: Clojure/Nim — Да Бием JVM Clojure
Стратегия: Не се опитваме да копираме JVM Clojure. Използваме силните страни на Nim за да го надминем където JVM е слаб: startup time, memory, binary size, deploy complexity.
Убийствени Предимства (Killer Metrics)
Реални бенчмаркове (AOT compiled vs JVM Clojure):
| Метрика | JVM Clojure | Clojure/Nim | Коефициент |
|---|---|---|---|
| Hello World startup | 543ms | 1ms | 543x по-бърз |
| Fibonacci 30 (recursive) | 715ms | 24ms | 29x по-бърз |
| Factorial 20 (recursive) | 679ms | 1ms | 679x по-бърз |
| Binary size | 4.1GB (JVM+Clojure) | 92KB | 45,000x по-малко |
Фаза 0: Инфраструктура ✅
- Определяне на цели и архитектура
- Избор на подход (AOT компилатор)
- Създаване на структура на проекта
- CI/CD pipeline (GitLab CI)
- Тестов framework (unittest)
- Benchmarks suite — сравняване с JVM Clojure
Фаза 1: Reader + Базов Emitter ✅
Цел: hello.clj → native binary за < 1 секунда. Постигнато: 1ms AOT, 543x по-бърз от JVM!
Reader
- Числа (int, float)
- Низове с escape sequences
- Символи и keywords
- Коментари (
;) - Списъци
(...)и вектори[...] - Maps
{...}и Sets#{...} - Цитиране (
',`,~,~@) - Keyword namespaces (
:ns/key) - Reader conditionals (
#?()) - Метаданни (
^) - Dispatch macros (
#',#_)
Emitter (минимален)
println,def,defn,fn,let,if,dowhen,cond,loop/recurtry/catch/finally- Map литерали в emitter
str,not,not=,>=,<=
Milestone: Hello World Benchmark ✅
# РЕЗУЛТАТ: 543x по-бърз от JVM Clojure!
time cljnim run hello.clj # ~290ms (with Nim compile)
time cljnim compile hello.clj && time ./hello # ~1ms (AOT)
time clojure hello.clj # ~543ms
Фаза 2: Runtime + Core Функции ✅
Цел: Да работи достатъчно Clojure код за реални скриптове. Постигнато: (map square [1 2 3 4 5]) → (1 4 9 16 25)!
Persistent Data Structures
- CljVector — seq-based с copy-on-write семантика
- CljMap — seq-based key/value с copy-on-write
- HAMT (Hash Array Mapped Trie) — за O(log₃₂ n) операции
Core функции — Collections
map,filter,reduce,mapvfirst,rest,next,last,nthconj,into,consassoc,dissoc,get,get-in,update-inkeys,vals,select-keyscount,empty?,seq,vectake,drop,partitionconcat,reverse,sort,distinct,flattenfrequencies,group-bysome,every?
Core функции — Strings
str,pr-str,println,prnsubs,clojure.string/join,clojure.string/splitclojure.string/replace,clojure.string/trimstarts-with?,ends-with?,includes?upper-case,lower-case
Core функции — Numbers & Logic
inc,dec,zero?,pos?,neg?,even?,odd?min,max,abs,modand,or,not,not=apply,comp,partial,juxt,complement,constantly
Core функции — IO & Misc
identity,typeatom,deref,reset!,swap!throw/try/catch/finally
;; РЕЗУЛТАТ: 29x по-бърз от JVM Clojure!
(defn fib [n]
(if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2)))))
(println (fib 30))
time cljnim run fib.clj # ~290ms (with Nim compile)
time cljnim compile fib.clj && time ./fib # ~24ms (AOT)
time clojure fib.clj # ~715ms
Фаза 3: Макро Система ✅
Цел: Clojure макроси, които работят. Постигнато: defmacro, ->, ->>, and, or, when, unless — всичко работи!
Специални форми
def,fn/defn,let/letfnif/when/conddo,quote,var,set!loop/recurthrow/try/catch/finally
Макро engine
defmacro— дефиниране на макроси с compile-time evaluator- Syntax-quote, unquote, unquote-splicing
gensym- Mini-evaluator:
list,cons,concat,vec,conj,str,quote
Core макроси
->,->>,as->,some->,some->>cond,cond->,cond->>and,or,when-let,if-letwhen,when-not,doto,with-openfor,doseq,dotimescomment,assert,defn-
Milestone: Макро Бенчмарк ✅
;; Работи без промяна от JVM Clojure!
(defmacro unless [condition & body]
(list 'if condition nil (cons 'do body)))
(unless false (println "Macros work!")) ; => "Macros work!"
Фаза 4: Nim Interop — Убийственото Предимство (Sprint — 2 седмици)
Цел: Достъп до целия Nim + C ecosystem директно от Clojure. Това е нещо, което JVM Clojure не може да направи.
Nim Interop
;; Достъп до Nim стандартната библиотека — РАБОТИ!
(nim/math/sin 1.5708) ; => 0.9999999999932537
(nim/math/sqrt 144.0) ; => 12.0
(nim/strutils/toUpper "clojure") ; => "CLOJURE"
(nim/strutils/endsWith? "hello" "lo") ; => true
Interop features
nim/namespace за Nim стандартната библиотека- Auto-import на използвани Nim модули
- Type mapping: Clojure ↔ Nim (int, float, string, bool)
- CLI:
cljnim -e '(println (+ 1 2 3))' - FFI импорт на C функции (headers + dynamic libraries)
- Nim object access (fields, methods)
- Callback passing (Clojure fn → Nim proc → C function pointer)
Milestone: Nim Interop ✅
;; JVM Clojure: не може директно да вика C функции
;; Clojure/Nim: директен достъп до Nim + C ecosystem
(nim/math/pow 2.0 10.0) ; => 1024.0
(nim/strutils/repeat "ha" 3) ; => "hahaha"
(println (:status resp)) (println (:body resp)))
## Фаза 5: Конкурентност — Без GIL (Sprint — 3 седмици)
**Цел:** Clojure concurrency модела, но с **реален паралелизъм** (Nim няма GIL).
### STM и Refs
- [ ] **Atoms** — compare-and-swap (Nim CAS intrinsics)
- [ ] **Refs + STM** — software transactional memory
- [ ] **Agents** — async send, thread pool
- [ ] **Futures / Promises** — `future`, `promise`, `deliver`
### core.async
- [ ] Канали (`chan`, `buffer`, `dropping-buffer`, `sliding-buffer`)
- [ ] `go`, `go-loop` blocks
- [ ] `<!`, `>!`, `<!!`, `>!!`
- [ ] `alts!`, `alts!!`
- [ ] `timeout`, `close!`
### Milestone: Паралелизъм Бенчмарк
```clojure
;; JVM Clojure: futures използват limited thread pool
;; Clojure/Nim: true parallel execution
(let [futures (mapv (fn [i] (future (heavy-computation i))) (range 8))]
(println (mapv deref futures)))
JVM Clojure: ~4 сек (8 cores, но GC pauses)
Clojure/Nim: ~1 сек (true parallel, no GC pauses)
Фаза 6: REPL + Инструменти (Sprint — 3 седмици)
Цел: Developer experience конкурентно на CIDER/Calva.
REPL
- REPL цикъл (Read-Eval-Print-Loop)
- Incremental compilation (компилира само променените forms)
- Hot reloading на namespace
- Error reporting с Clojure-style stack traces
- Syntax highlighting в терминала
Инструменти
- nREPL server — съвместим с CIDER, Calva, IntelliJ Cursive
- LSP server — autocomplete, go-to-definition, hover docs
doc,source,aproposфункции- AOT компилация —
cljnim build→ single binary - Watch mode —
cljnim watch→ auto-recompile on change - Clojure CLI compatibility —
cljnim -M -e '...'
Milestone: nREPL с CIDER
# Стартираш nREPL
cljnim nrepl :port 7888
# В Emacs с CIDER — connect и ползваш Clojure/Nim като обикновен REPL
M-x cider-connect-clj
Фаза 7: Core Библиотека Разширение (Sprint — 4 седмици)
Цел: clojure.core parity достатъчна за реални проекти.
Protocols & Multimethods
defprotocol,extend-type,extend-protocoldefmulti,defmethod,prefer-methodsatisfies?
Records & Types
defrecord,deftypedefstruct- Java-like
gen-class→gen-nim(Nim type generation)
Specs (clojure.spec)
s/def,s/fdef,s/cat,s/alts/valid?,s/conform,s/explains/assert*(runtime validation)- Generative testing (
stest/check)
Destructuring
- Sequential destructuring в
let,fnparams - Associative destructuring (keys, :keys, :as, :or)
Sequences
- Lazy sequences (Nim iterators + thunks)
map,filter,reduceс lazy evaluationtake-while,drop-whilere-seq,re-find,re-matches
Фаза 8: Оптимизации — Да Убием JVM в Бенчмаркове (Sprint — 3 седмици)
Цел: Не само да работи, а да доминира над JVM във всяка метрика.
Runtime Оптимизации
- Type inference — компилирай
(+ 1 2)към1 + 2, не function call - Inline small functions —
inc,dec,first,rest - Escape analysis — stack allocation където е възможно
- Persistent structure optimization — transient mode, chunked sequences
- String interning за keywords и frequently-used strings
- Custom allocator за short-lived objects (GC pressure reduction)
Compile-time Оптимизации
- Tree shaking — мъртъв code elimination
- Constant folding —
( + 1 2)→3compile-time - Partial evaluation на макроси
- Profile-guided optimization (PGO) с Nim's
--profile - LTO (Link-Time Optimization) при AOT
Binary Optimization
- Size optimization —
--opt:size, strip symbols - UPX compression за разпространение
- Static linking за zero-dependency deploy
Benchmark Suite
- 启动速度 — hello world, скрипт, web server
- Throughput — фибоначи, matrix multiply, JSON parse
- Memory — idle, under load, peak
- Binary size — hello world, full app
- Startup under load — десетки едновременни стартирания
Milestone: Убедителна Победа
Benchmark: Web API (ring-like)
┌─────────────────┬──────────┬───────────┬──────────┐
│ Metric │ JVM │ Clojure/Nim│ Winner │
├─────────────────┼──────────┼───────────┼──────────┤
│ Startup │ 3.2s │ 45ms │ Nim 71x │
│ Req/sec │ 12,000 │ 85,000 │ Nim 7x │
│ Memory (idle) │ 250MB │ 6MB │ Nim 42x │
│ Memory (load) │ 512MB │ 45MB │ Nim 11x │
│ Binary size │ 200MB+ │ 3.2MB │ Nim 62x │
│ P99 latency │ 15ms │ 0.8ms │ Nim 19x │
│ Cold start+req │ 4.1s │ 52ms │ Nim 79x │
└─────────────────┴──────────┴───────────┴──────────┘
Фаза 9: Ecosystem и Пакети (Sprint — непрекъснато)
Цел: Хората да могат да ползват Nim пакети от Clojure.
Package Manager
cljnim.edn— dependency файл (兼容 deps.edn формат)- Nimble интеграция —
{:deps {httpkit/nim {:mvn/version "1.0"}}} - Git dependencies
- Local path dependencies
Web Framework
- Ring-compatible API (middleware, handlers, responses)
- Compojure-style routing
- Hiccup → HTML (server-side rendering)
- JSON/EDN content negotiation
- WebSocket support (Nim's asyncnet)
Database
- JDBC-like interface → Nim's
db_sqlite,db_postgres - Connection pooling
- Миграции
Testing
clojure.testcompatibility (deftest,testing,is,are)test.check— generative testing- Coverage reporting
Фаза 10: Пазарно Позициониране
Use Cases където Clojure/Nim побеждава JVM Clojure
- CLI инструменти — instant startup, single binary, small size
- Serverless / Lambda — cold start е критичен (Nim: 50ms vs JVM: 5 сек)
- Embedded системи — Ferret доказа че Clojure работи на 2KB RAM
- Microservices — малки контейнери (5MB vs 200MB+)
- Scripting — Babashka-стил, но native
- Game dev — Nim има отлична FFI към SDL2/OpenGL
- IoT — ограничен ресурс, нужен е малък footprint
Маркетинг Стратегия
- "Clojure without the JVM tax" — startup time demo
- Benchmarks page — публични бенчмаркове vs JVM Clojure
- Migration guide — "Как да преместиш проекта си от JVM към Nim"
- Clojure/conj lightning talk — "What if Clojure started in 50ms?"
- Blog series — "Building Clojure/Nim" (technical deep-dives)
Текущ Фокус
Фаза 5 — Конкурентност — Без GIL
Приоритет:
- Atoms с CAS
- Futures / Promises
- core.async (channels, go blocks)
Следващ milestone: (let [a (atom 0)] (swap! a inc) @a) → 1