diff --git a/NEXT.md b/NEXT.md index aaa2bee..5ffde47 100644 --- a/NEXT.md +++ b/NEXT.md @@ -590,6 +590,34 @@ Two smaller findings, both written down beside the code that ran into them: Already present and easy to miss: an **EDN parser**, at `vendor/edn/edn.flan`. +## Decided: the Clojure patterns we are deliberately not copying + +This language borrows Clojure's shape and is **not** trying to be Clojure-compatible, so its known wrinkles are ours +to avoid rather than inherit. Four, with what to do instead. + +**1. One argument-order rule, held everywhere.** Clojure's sequence functions take the collection *last* +(`(map f coll)`) and its collection functions take it *first* (`(assoc m k v)`). The split is deliberate there, and it +is why Clojure needs **two** threading macros instead of one. **Our rule: the thing being operated on comes first.** +That is already what the language does — `(at a i)`, `(len xs)`, `(push v x)`, `(as-slice v)` — and `into` follows it +with the source first. Hold it; do not ship two of anything to paper over a split. + +**2. A membership test says which thing it tests.** Clojure's `contains?` checks *keys*, so `(contains? [1 2 3] 1)` is +true because index 1 exists — the most-cited confusion in the language, and there is no built-in for "is this value in +this list". Half of this is already right here: `has-key?` on a `Map` is named for what it does. If a value-membership +test is added for sequences, name it for values and never overload one name across both meanings. + +**3. A predicate returns a boolean; a search returns what it found.** Clojure's `some` returns the *value*, so +`(some even? [1 2])` is `true` but `(some identity [nil false])` is `nil` — one name doing two jobs. Keep them apart: +a `?` name answers yes or no, a finder answers the thing or nothing, and neither pretends to be the other. + +**4. Composition reads in the same direction as threading.** Clojure's `comp` is right-to-left while `->` is +left-to-right, so the two compose mentally in opposite directions. If anything here ever composes operations, it reads +left to right, the way `into` does. + +Sources are community consensus rather than a specification; the `contains?` complaint is documented in *Getting +Clojure*. Recorded because these are cheap to honour now and expensive to unpick once a standard library depends on +them. + ## Queued: `into`, fused transformation without transducers Decided in conversation. **Not transducers, and not Rust's iterators — a macro that fuses the chain at compile time.**