From e4153419d3726c17babb3336a41027724e6e1882 Mon Sep 17 00:00:00 2001 From: Martin Muskov <65186527+martin-k-m@users.noreply.github.com> Date: Wed, 2 Sep 2026 22:30:39 -0500 Subject: [PATCH 1/2] sorted_copy is the builtin now twill 1.9.0 orders a list of numbers, which is docs/needs.md entry 8, so the insertion sort in src/bars.tw becomes one line and weft ships no sort of its own. The old comment defended the quadratic version on the grounds that a histogram is drawn once per plot rather than per frame. That defence was fair and is no longer needed: it is not the simpler code any more, only the slower one. Co-Authored-By: Claude Opus 5 --- docs/needs.md | 18 ++++++++++-------- src/bars.tw | 34 +++++++++++----------------------- 2 files changed, 21 insertions(+), 31 deletions(-) diff --git a/docs/needs.md b/docs/needs.md index af592c0..4575abc 100644 --- a/docs/needs.md +++ b/docs/needs.md @@ -162,14 +162,16 @@ conversion to `Str` fixes it without a new type. **Needs:** a sort on `Arr[F64]`, or a comparator-taking sort on `Arr[T]` **Used by:** `src/bars.tw` (`sorted_copy`, for the quartiles that set the histogram bin width) -**Status:** **open.** 1.7.1 has a systems-mode `sort`, but only on strings: -`sort` on an `Arr[F64]` is `runtime error: sort on a list expects every element -to be a string`. numeric mode has `sort`, `argsort` and `topk` on tensors. There -is still no ordering operation for `Arr[F64]` and no comparator-taking sort. - -weft ships an insertion sort. It is correct and it is quadratic, and it is called -on the caller's entire sample. It is acceptable only because a histogram is drawn -once rather than per frame, and that is not a property to rely on. +**Status: delivered in twill 1.9.0, and taken up.** `sort` orders a list of +numbers and takes a comparison, so `sorted_copy` is one line and weft ships no +sort of its own. + +What it said while it was open, because the reasoning is the record: 1.7.1's +systems-mode `sort` accepted strings only, so `sort` on an `Arr[F64]` was +`runtime error: sort on a list expects every element to be a string`, and weft +shipped an insertion sort that was correct, quadratic, and called on the +caller's entire sample. It was acceptable only because a histogram is drawn once +rather than per frame, and that is not a property to rely on. ### 9. Immutable top-level bindings diff --git a/src/bars.tw b/src/bars.tw index 229a532..8797fe0 100644 --- a/src/bars.tw +++ b/src/bars.tw @@ -178,29 +178,17 @@ fn quantile(sorted: Arr[F64], q: F64) -> F64 { sorted[i] * (1.0 - frac) + sorted[i + 1] * frac } -# Insertion sort. The only caller is the quartile calculation on a sample that -# is already in memory, and a histogram is drawn once per plot rather than per -# frame, so the simpler code wins over the faster one. -fn sorted_copy(xs: Arr[F64]) -> Arr[F64] { - let out: Arr[F64] = [] - let i: I64 = 0 - while i < len(xs) { - out.push(xs[i]) - i = i + 1 - } - let a: I64 = 1 - while a < len(out) { - let v = out[a] - let b = a - 1 - while b >= 0 && out[b] > v { - out[b + 1] = out[b] - b = b - 1 - } - out[b + 1] = v - a = a + 1 - } - out -} +# The builtin sort, behind weft's own name. +# +# This was an insertion sort until twill 1.9.0, and the comment defended it on +# the grounds that a histogram is drawn once per plot rather than per frame. The +# defence was fair and is no longer needed: `sort` orders a list of numbers now +# (docs/needs.md entry 8), so the quadratic version is not the simpler code any +# more, it is just the slower one. +# +# It copies rather than sorting in place, which is what the caller wants and +# what the builtin does anyway. +fn sorted_copy(xs: Arr[F64]) -> Arr[F64] = sort(xs) fn cbrt(v: F64) -> F64 = exp(log(v) / 3.0) From cab10aaab3391c60578cd4b11fd774763a426d58 Mon Sep 17 00:00:00 2001 From: Martin Muskov <65186527+martin-k-m@users.noreply.github.com> Date: Wed, 2 Sep 2026 23:27:17 -0500 Subject: [PATCH 2/2] Pin twill 1.9.0, the release that has the sort CI installs v1.9.0 and spool.toml asks for ^1.9.0, because the sort this branch adopts is in that release and not in the one pinned before it. Co-Authored-By: Claude Opus 5 --- .github/workflows/ci.yml | 4 ++-- spool.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa2c1ba..a01aea8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -84,10 +84,10 @@ jobs: # would have. Pinned rather than floating: a green run should mean this # code passed against a known compiler, not against whatever was newest # that morning. - - name: Install twill v1.7.1 + - name: Install twill v1.9.0 run: | curl -fsSL -o twill \ - https://github.com/twill-lang/twill/releases/download/v1.7.1/twill-v1.7.1-linux-amd64 + https://github.com/twill-lang/twill/releases/download/v1.9.0/twill-v1.9.0-linux-amd64 chmod +x twill ./twill --version diff --git a/spool.toml b/spool.toml index 6ae7637..f33e363 100644 --- a/spool.toml +++ b/spool.toml @@ -12,4 +12,4 @@ entry = "src/chart.tw" # minimum this code actually compiles under rather than the newest release at # the time of writing. See the note in README.md and docs/needs.md. [dependencies] -twill = { version = "^1.7.0", git = "https://github.com/twill-lang/twill" } +twill = { version = "^1.9.0", git = "https://github.com/twill-lang/twill" }