From 5ea0bcae841881f75fa7a6e1de3e7b7da00b6a38 Mon Sep 17 00:00:00 2001 From: Joseph Ferano Date: Sat, 12 Sep 2026 04:46:41 +0700 Subject: [PATCH] Remove nth, the alias that was not one nth and at were documented as the same operation, and as reads they were: check.ml matched "at" | "nth" in one arm. But a place is recovered in two other spots -- parse.ml for (set ...) and place_of_expr for (addr ...) -- and both match only Sym "at". So (set (nth a i) x) and (addr (nth a i)) were refused while the at forms worked. Two names said to be identical that disagree about writing is worse than one name, and the asymmetry is not worth fixing in three places to keep a synonym. at is the indexing operation; nth is gone. The six call sites were all reads, so they rewrite directly. get/put stay the Map pair: get returns (Option V) and is deliberately not a place. nth-gone.flan pins the removal -- it has to fail as a name nobody defined, not quietly resolve to at again. destructure~nth is compiler-generated and unrelated. --- calc-me.flan | 2 +- lib/check.ml | 2 +- plan.org | 2 +- sand.flan | 8 ++++---- syntax-sketch.flan | 2 +- test/programs/nth-gone.flan | 11 +++++++++++ test/test_acceptance.ml | 5 +++++ web/index.html | 3 ++- 8 files changed, 26 insertions(+), 9 deletions(-) create mode 100644 test/programs/nth-gone.flan diff --git a/calc-me.flan b/calc-me.flan index e0e17a0..dfcccd2 100644 --- a/calc-me.flan +++ b/calc-me.flan @@ -120,6 +120,6 @@ (defn main [args [string]] i32 (if (< (len args) 2) (do (print-line "usage: calc-me \"1 + 2 * 3\"") 1) - (match (evaluate (bytes (nth args 1))) + (match (evaluate (bytes (at args 1))) (Some v) (do (print-f64 v) (print-line "") 0) None (do (print-line "calc-me: cannot parse") 1)))) diff --git a/lib/check.ml b/lib/check.ml index 59ba57f..508c7e7 100644 --- a/lib/check.ml +++ b/lib/check.ml @@ -1128,7 +1128,7 @@ and named_call ctx ~want loc name args = | other -> fail loc "len takes an array, a slice or a string, found %s" (Types.to_string other)); prim Tast.Len index_ty [ a ] - | "at" | "nth" -> + | "at" -> (match args with | target :: idx when idx <> [] -> let target = check ctx target in diff --git a/plan.org b/plan.org index e635d9c..0011baf 100644 --- a/plan.org +++ b/plan.org @@ -104,7 +104,7 @@ world. is type-directed: ~(defvar enemies (Map string Enemy) (map-new))~. ~get~ returns ~(Option V)~; ~put~ is the `Unit`-returning upsert. See spec-memory.md for the deferred move-aware operations. -- Operations: ~get~, ~put~, ~remove~, ~push~, ~pop~, ~nth~, ~len~, ~update~. +- Operations: ~get~, ~put~, ~remove~, ~push~, ~pop~, ~at~, ~len~, ~update~. Copying is explicit: ~(clone m)~, and owning containers move rather than copy on assignment. No ~!~ convention — nothing is immutable, so it would carry no information. No ~assoc~; it only existed as the copy-returning form. diff --git a/sand.flan b/sand.flan index ce84c07..adbb6d4 100644 --- a/sand.flan +++ b/sand.flan @@ -82,7 +82,7 @@ (>= c 0) (< c (- cols 1)) (empty-at? r c) (< (rand-f32) 0.5)) - (set (at grid r c) (nth colors current-color)) + (set (at grid r c) (at colors current-color)) (set (at velocity r c) 1.0))))))) (defn move-grain [from-row i32 from-col i32 @@ -198,7 +198,7 @@ rl/white) (rl/draw-texture brush 20 50 rl/white) (rl/draw-texture-v brush (rl/Vector2 {:x 44.0 :y 50.0}) - (rl/get-color (nth colors current-color))) + (rl/get-color (at colors current-color))) (rl/draw-texture-ex brush (rl/Vector2 {:x 72.0 :y 46.0}) 0.0 2.0 rl/white))) ;; The mirrored one beside them, scaled up so the flip is visible rather ;; than eight pixels wide. If the two badges look the same, either the flip @@ -449,7 +449,7 @@ ;; and does not. (defn draw-world-cursor [] (let [p (rl/get-screen-to-world-2d (rl/get-mouse-position) view) - tint (rl/get-color (nth colors current-color)) + tint (rl/get-color (at colors current-color)) x (.x p) y (.y p) r (f32 (* brush-size cell-size))] @@ -528,7 +528,7 @@ sh (- (rl/get-screen-height) 40)] (dotimes [i (len colors)] (let [cx (- sw (* (- (len colors) (+ i 1)) 46)) - c (rl/get-color (nth colors i))] + c (rl/get-color (at colors i))] (rl/draw-circle cx sh (f32 16.0) c) (when (= i current-color) (rl/draw-circle-lines cx sh (f32 22.0) rl/white)))) diff --git a/syntax-sketch.flan b/syntax-sketch.flan index 23f1d03..3afe994 100644 --- a/syntax-sketch.flan +++ b/syntax-sketch.flan @@ -58,7 +58,7 @@ ;; this frame (spec-memory.md, non-escaping fn). (defn largest [xs [a] gt (Fn [a a] bool)] (Option a) (if (> (len xs) 0) - (Some (reduce (fn [x y] (if (gt x y) x y)) (nth xs 0) xs)) + (Some (reduce (fn [x y] (if (gt x y) x y)) (at xs 0) xs)) None)) ;; (largest hps >) — `>` at i32 is an ordinary function value diff --git a/test/programs/nth-gone.flan b/test/programs/nth-gone.flan new file mode 100644 index 0000000..e338553 --- /dev/null +++ b/test/programs/nth-gone.flan @@ -0,0 +1,11 @@ +;;;; nth was an alias of at, and an asymmetric one: the checker accepted it as +;;;; a read, but parse.ml and place_of_expr both match only [at], so +;;;; (set (nth a i) x) and (addr (nth a i)) were refused while the [at] forms +;;;; worked. Two names documented as identical that disagree about writing are +;;;; worse than one name, so nth is gone and this pins the removal: it must +;;;; fail as an unknown name, not quietly resolve to at again. + +(defvar a [4 i32]) + +(defn main [] i32 + (nth a 0)) diff --git a/test/test_acceptance.ml b/test/test_acceptance.ml index 21ac026..398a605 100644 --- a/test/test_acceptance.ml +++ b/test/test_acceptance.ml @@ -620,6 +620,11 @@ let () = "one directory is one set of names"; refuses "two mains in one program" "programs/pkg-two-mains.flan" "main is defined twice"; + (* nth is gone, not renamed: it has to fail as a name nobody defined. If it + were ever re-added as an alias of [at] it would have to be a place too, + and this row is what says so. *) + refuses "nth is not a name" "programs/nth-gone.flan" + "unknown function nth"; (* ── wasm32 (NEXT.md, deferred item 6) ────────────────────────────── The second target, and the reason sand-headless imports no raylib. What diff --git a/web/index.html b/web/index.html index 5ec6791..73e630d 100644 --- a/web/index.html +++ b/web/index.html @@ -643,8 +643,9 @@ second

Arrays and slices

-

at and nth are the same operation and take any number of +

at indexes a fixed array or a slice, and takes any number of indices, so (at grid r c) indexes a two-dimensional fixed array directly. +It is a place: (set (at grid r c) v) and (addr (at grid r c)) both work. len works on a fixed array, a slice or a string. (slice s lo hi) takes a half-open range and never copies.