benchmarks/sql cleanup + linq_decs tutorial + linq-fold patterns reference#2843
Merged
borisbat merged 3 commits intoMay 24, 2026
Merged
Conversation
Trims each bench to three lanes (SQL / Array / Decs == m1 / m3f / m4) by dropping the m3 eager-linq lane that the splice ladder rendered redundant; also drops sort_take's legacy m3_topn_array / m3_topn_iter algorithm-comparison wrappers. Back-fills the SQL lane for join_count (sqlite_linq's _join+_select accepts the chain when the projection is a named tuple — the existing "db handle wiring" comment was wrong about the real blocker, which was the positional-tuple shape). Refreshes the 5 keep-out comments (distinct_by_count, groupby_first, groupby_select_sum, take_count_filtered, take_sum_aggregate) with dated TODO markers quoting the actual sqlite_linq error each chain produces, and the 2 by-design absences (take_*_aggregate LIMIT-on-aggregate semantics, zip_dot_product no relational analog). The join_count decs (m4) lane stays absent with a TODO referencing plan_join in linq_fold.das. Adds benchmarks/sql/results.md with both INTERP and JIT tables (generated 2026-05-23 from master 1c8ff91) plus per-gap footnotes that quote each ".das" source comment verbatim so the file is the single source of truth for "why is this cell empty." Updates benchmarks/README.md sql/ section with a per-file table. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds tutorials/language/55_linq_decs.das (runnable, self-contained [export] def main) covering from_decs_template, the _fold splice over decs entities, and three canonical chain shapes (where+count, order_by+first streaming-min, group_by+select). Paired RST at doc/source/reference/tutorials/55_linq_decs.rst with the standard label / seealso / download blocks; added to the language toctree after 54_glob. Adds doc/source/reference/linq_fold_patterns.rst — a lookup-oriented catalog of every chain shape that _fold recognizes, with the splice arm (plan_*/emit_* in daslib/linq_fold.das) each one fires. Organized by source type (array vs decs vs zip) plus a "what falls back" tail listing the chains that drop to fold_linq_default. Linked from the reference toctree (doc/source/reference/index.rst). Links the new patterns page from the linq_fold module docs by adding a "See also" block to doc/source/stdlib/handmade/module-linq_fold.rst (the handmade source that feeds the generated linq_fold.rst). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This pull request cleans up the SQL benchmark suite (removing the legacy “m3” eager-LINQ lane and refreshing notes/results), and adds new end-user documentation: a runnable “LINQ over DECS” tutorial plus a reference catalog of _fold-recognized chain shapes (wired into the Sphinx docs and stdlib module page).
Changes:
- Benchmarks: remove the
m3lane across SQL benches, refresh “keep-out” comments with concrete_sqlerrors, backfilljoin_countSQL lane, and addbenchmarks/sql/results.md+ expandbenchmarks/README.md. - Tutorials: add
tutorials/language/55_linq_decs.dasand its rendered RST page, and link it into the tutorials toctree. - Reference docs: add
linq_fold_patterns.rstand link it from the reference index andmodule-linq_fold“See also”.
Reviewed changes
Copilot reviewed 60 out of 60 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| benchmarks/README.md | Expands SQL benchmarks documentation and adds a per-file table of the SQL bench suite. |
| benchmarks/sql/aggregate_match.das | Removes m3 lane from aggregate benchmark (keeps SQL/array/decs lanes). |
| benchmarks/sql/all_match.das | Removes m3 lane from “all” benchmark. |
| benchmarks/sql/any_match.das | Removes m3 lane from “any” benchmark. |
| benchmarks/sql/average_aggregate.das | Removes m3 lane from average benchmark. |
| benchmarks/sql/bare_order_where.das | Removes m3 lane from order/where benchmark. |
| benchmarks/sql/chained_where.das | Removes m3 lane from chained filters benchmark. |
| benchmarks/sql/contains_match.das | Removes m3 lane from contains benchmark. |
| benchmarks/sql/count_aggregate.das | Removes m3 lane from count benchmark. |
| benchmarks/sql/distinct_by_count.das | Removes m3 lane; refreshes SQL keep-out note with concrete _sql error. |
| benchmarks/sql/distinct_count.das | Removes m3 lane from distinct benchmark. |
| benchmarks/sql/distinct_take.das | Removes m3 lane from distinct+take benchmark. |
| benchmarks/sql/element_at_match.das | Removes m3 lane from element_at benchmark. |
| benchmarks/sql/first_match.das | Removes m3 lane from first benchmark. |
| benchmarks/sql/first_or_default_match.das | Removes m3 lane from first_or_default benchmark. |
| benchmarks/sql/groupby_average.das | Removes m3 lane from group_by average benchmark. |
| benchmarks/sql/groupby_count.das | Removes m3 lane from group_by count benchmark. |
| benchmarks/sql/groupby_first.das | Removes m3 lane; updates SQL keep-out note re: “first per group”. |
| benchmarks/sql/groupby_having_count.das | Removes m3 lane from group_by having benchmark. |
| benchmarks/sql/groupby_having_hidden_sum.das | Removes m3 lane from group_by having (hidden sum) benchmark. |
| benchmarks/sql/groupby_max.das | Removes m3 lane from group_by max benchmark. |
| benchmarks/sql/groupby_min.das | Removes m3 lane from group_by min benchmark. |
| benchmarks/sql/groupby_multi_reducer.das | Removes m3 lane from multi-reducer group_by benchmark. |
| benchmarks/sql/groupby_select_sum.das | Removes m3 lane; refreshes SQL keep-out note re: expression keys in _group_by. |
| benchmarks/sql/groupby_sum.das | Removes m3 lane from group_by sum benchmark. |
| benchmarks/sql/groupby_where_count.das | Removes m3 lane from group_by+where count benchmark. |
| benchmarks/sql/groupby_where_sum.das | Removes m3 lane from group_by+where sum benchmark. |
| benchmarks/sql/indexed_lookup.das | Removes m3 lane from indexed lookup benchmark. |
| benchmarks/sql/join_count.das | Removes m3 lane; backfills join_count SQL lane behavior and updates notes. |
| benchmarks/sql/last_match.das | Removes m3 lane from last benchmark. |
| benchmarks/sql/long_count_aggregate.das | Removes m3 lane from long_count benchmark. |
| benchmarks/sql/max_aggregate.das | Removes m3 lane from max benchmark. |
| benchmarks/sql/min_aggregate.das | Removes m3 lane from min benchmark. |
| benchmarks/sql/order_take_desc.das | Removes m3 lane from order/take descending benchmark. |
| benchmarks/sql/results.md | Adds benchmark result tables + footnotes/notes on missing lanes and probe errors. |
| benchmarks/sql/reverse_take.das | Removes m3 lane from reverse+take benchmark. |
| benchmarks/sql/select_count.das | Removes m3 lane from select+count benchmark. |
| benchmarks/sql/select_where.das | Removes m3 lane from select+where benchmark. |
| benchmarks/sql/select_where_count.das | Removes m3 lane from select+where+count benchmark. |
| benchmarks/sql/select_where_order_take.das | Removes m3 lane from select+where+order+take benchmark. |
| benchmarks/sql/select_where_sum.das | Removes m3 lane from select+where+sum benchmark. |
| benchmarks/sql/single_match.das | Removes m3 lane from single benchmark. |
| benchmarks/sql/skip_take.das | Removes m3 lane from skip+take benchmark. |
| benchmarks/sql/skip_while_match.das | Removes m3 lane from skip_while benchmark. |
| benchmarks/sql/sort_first.das | Removes m3 lane from sort_first benchmark. |
| benchmarks/sql/sort_take.das | Removes m3 lane and drops legacy m3_topn_array/m3_topn_iter wrappers. |
| benchmarks/sql/sum_aggregate.das | Removes m3 lane from sum benchmark. |
| benchmarks/sql/sum_where.das | Removes m3 lane from sum_where benchmark. |
| benchmarks/sql/take_count.das | Removes m3 lane from take+count benchmark. |
| benchmarks/sql/take_count_filtered.das | Removes m3 lane; updates SQL note re: LIMIT-on-aggregate semantics. |
| benchmarks/sql/take_sum_aggregate.das | Removes m3 lane; updates SQL note re: LIMIT-on-aggregate semantics. |
| benchmarks/sql/take_while_match.das | Removes m3 lane from take_while benchmark. |
| benchmarks/sql/to_array_filter.das | Removes m3 lane from to_array+filter benchmark. |
| benchmarks/sql/zip_dot_product.das | Removes m3 lane; refreshes SQL keep-out note for zip non-relationality. |
| doc/source/reference/index.rst | Links the new linq-fold patterns reference from the main reference index. |
| doc/source/reference/linq_fold_patterns.rst | Adds a catalog of _fold-recognized chain shapes and their splice arms. |
| doc/source/reference/tutorials.rst | Adds tutorial 55 to the language tutorials toctree. |
| doc/source/reference/tutorials/55_linq_decs.rst | Adds the rendered Sphinx tutorial page for LINQ over DECS. |
| doc/source/stdlib/handmade/module-linq_fold.rst | Adds a “See also” link from the linq_fold module docs to the new patterns reference. |
| tutorials/language/55_linq_decs.das | Adds a runnable tutorial demonstrating _fold over DECS (count, order_by+first, group_by+select). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Drop `from_decs` (runtime-list form) from the 55_linq_decs tutorial header bullets and RST index — tutorial body only demonstrates `from_decs_template`; mention `from_decs` in the RST intro as explicitly out of scope. - Fix benchmarks/README.md sql/ lane table: the Decs lane uses `from_decs_template(type<DecsCar>)`, not `type<Car>` — `DecsCar` is the `[decs_template]` fixture in `_common.das`. - Rewrite linq_fold_patterns.rst dispatch-order section to match the actual `LinqFold.visit` sequence (12 steps, decs/array variants interleaved per source-type-first matching), instead of the abstract "Decs source → Zip → Array" grouping that didn't match the code. - linq_fold_patterns.rst Array-source `count` row: replace "Per-archetype counter" (decs terminology) with "Single counter, no allocation; one pass over the array." - benchmarks/sql/results.md: switch the embedded `_sql` error messages from single-backtick inline code (which can't contain backticks) to fenced code blocks. GitHub markdown rendering now shows the error text verbatim. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced May 24, 2026
pull Bot
pushed a commit
to forksnd/daScript
that referenced
this pull request
May 24, 2026
… review fixes Two improvements this PR: 1. Expression-key support in `_group_by` (Session 2 from the post-PR GaijinEntertainment#2843 plan). `_group_by(_.Price % 100)` (and tuples mixing field keys with expression keys) now lower to `GROUP BY ((price) % (100))`. The rendered fragment is reused verbatim in SELECT (`K = _._0`) and ORDER BY (`_order_by(_._0)`) positions, so the SQL stays a single source of truth across all three clauses. Mechanism: `collect_group_keys` calls `pred_to_sql` with a new `q.inlineConstants` mode so the bound `_.X` field refs render as columns and `ExprConst*` literals (ints, floats, strings, bools) inline as SQL literals instead of `?` placeholders. The fragment carries no binds, which lets us re-use it at multiple SQL positions without bind-position bookkeeping. Runtime values (`_.Col - capturedVar`) reject loudly with a precise diagnostic — same one exercised by `failed_sql_macro` case 25. Order swap in the `_group_by` peel: recurse into the source first so `q.rootType` is set before `pred_to_sql` runs on the key (the existing field-key path didn't need this since translation was deferred to emission; expression keys do). Backfills `benchmarks/sql/groupby_select_sum.das` m1 lane. The bench uses the explicit-inner-select shape inside SUM (`_._1 |> select($(c : Car) => c.price) |> sum()`) — m3f/m4 keep their splice-friendly bare-`sum` form; both emit equivalent SQL/compute. results.md refreshed per the living-doc policy, "Notes on missing lanes" bullet for `groupby_select_sum SQL` removed. 2. Two PR GaijinEntertainment#2845 review fixes (Copilot, both real): - `peel_count_terminal`'s predicate-overload error mis-named the terminal: it said `_count(predicate)` and suggested `_count()`, but in `_sql` chains the bare `count()` / `long_count()` linq functions are the actual terminals. Drop the underscores in both the offending name and the suggested fix. - `try_peel_distinct_by_field` pinned receiver to `ExprVar` but didn't verify the var IS the lambda's bound parameter. So `_distinct_by(capturedRow.Brand) |> count()` would silently emit `COUNT(DISTINCT "Brand")` against the SQL source — wrong result, no diagnostic. Now extracts the lambda's arg name from `keyLambda._block.arguments[0]` and rejects when receiver name differs (`failed_sql_macro` case 24). Test surface: - `tests/dasSQLITE/test_32_group_by_expression_keys.das` — 6 tests covering SQL emission + runtime for single expression keys, multi-key tuples mixing field + expression keys, ORDER BY on the group key, and aggregate-over-expression-key projection. - `failed_sql_macro.das` cases 24 + 25 added (50503:23). Validation: 796/796 dasSQLITE (interp + AOT), 1390/1390 linq, 0 JIT bench failures, lint clean. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three threads, each on its own commit:
Commit 1 — bench cleanup + results.md (
benchmarks/sql/, 54 files):m3eager-linq lane across all 52 bench files (the splice ladder closed the gap, m3 was no longer a useful comparison point). Also dropssort_take's legacym3_topn_array/m3_topn_iteralgorithm-comparison wrappers.join_countSQL lane — sqlite_linq accepts the chain when the projection is a named tuple ((CarName=c.name, DealerName=d.name)). The existing comment about "db handle wiring" was wrong about the actual blocker._sqlerror each probe produced:distinct_by_count—_sql: unsupported chain root or operator. Got: __::linq`distinct_by`...groupby_select_sum—_sql: _group_by: key must be_.Fieldor a tuple of_.Fields; got: (_ % 100)groupby_first— no SQL "first per group" without window-function loweringtake_count_filtered/take_sum_aggregate— LIMIT-on-aggregate is semantically distinct in SQL (by design, no follow-up)zip_dot_product— zip is not a relational operation (by design)join_countstays absent — would need a Dealer[decs_template]+ nested-archetype hash index. TODO referenced in the bench file andresults.md.benchmarks/sql/results.mdwith two tables (INTERP + JIT) from master1c8ff9119, columns labeled SQL / Array / Decs (user-facing — drops the m1/m3f/m4 jargon), plus per-gap footnotes that quote each.dassource comment verbatim.benchmarks/README.mdsql/ section with a per-file table (was a one-line stub).Commit 2 — linq_decs tutorial (
tutorials/language/55_linq_decs.das+ RST):Runnable, self-contained
[export] def main()tutorial coveringfrom_decs_template, the_foldsplice over decs entities, and three canonical chain shapes (where+count, order_by+first streaming-min, group_by+select). Paired RST with standard label / seealso / download blocks; added to the language toctree after54_glob.Commit 2 also — linq-fold patterns reference (
doc/source/reference/linq_fold_patterns.rst):Lookup-oriented catalog of every chain shape that
_foldrecognizes, with the splice arm (plan_*/emit_*indaslib/linq_fold.das) each one fires. Organized by source type (array vs decs vs zip) plus a "what falls back" tail listing chains that drop tofold_linq_default. Linked from the reference toctree and from the handmademodule-linq_fold.rst"See also" block (which feeds the generatedstdlib/generated/linq_fold.rst).Follow-up TODOs spawned (none block this PR)
distinct_by_countprobe.groupby_firstprobe (would enableROW_NUMBER() OVER (PARTITION BY ...))._group_by— surfaced bygroupby_select_sumprobe.plan_join— surfaced byjoin_countdecs-lane analysis.Test plan
for f in benchmarks/sql/*.das; do mcp__daslang__lint "$f"; done— clean.bin/daslang dastest/dastest.das -- --test benchmarks/sql/— 0 errors, 0 tests, compile gate.results.md(sort_first m4=13.4, m3f=11.0).bin/daslang—host_jit_triplewas added recently).bin/daslang tutorials/language/55_linq_decs.dasexits 0 with the expected print output.rm -rf doc/sphinx-build site/doc && sphinx-build -b html -d doc/sphinx-build doc/source site/doc—build succeeded.with no new warnings vs master.doc/source/stdlib/generated/linq_fold.rstafterbin/daslang doc/reflections/das2rst.dascontains the:doc:link to/reference/linq_fold_patterns.🤖 Generated with Claude Code