Skip to content

benchmarks/sql cleanup + linq_decs tutorial + linq-fold patterns reference#2843

Merged
borisbat merged 3 commits into
masterfrom
bbatkin/bench-sql-cleanup-tutorials-patterns-doc
May 24, 2026
Merged

benchmarks/sql cleanup + linq_decs tutorial + linq-fold patterns reference#2843
borisbat merged 3 commits into
masterfrom
bbatkin/bench-sql-cleanup-tutorials-patterns-doc

Conversation

@borisbat
Copy link
Copy Markdown
Collaborator

Summary

Three threads, each on its own commit:

Commit 1 — bench cleanup + results.md (benchmarks/sql/, 54 files):

  • Drops the m3 eager-linq lane across all 52 bench files (the splice ladder closed the gap, m3 was no longer a useful comparison point). Also drops sort_take's legacy m3_topn_array / m3_topn_iter algorithm-comparison wrappers.
  • Backfills join_count SQL 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.
  • Refreshes the 5 keep-out comments with dated TODO markers quoting the actual _sql error 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 _.Field or a tuple of _.Field s; got: (_ % 100)
    • groupby_first — no SQL "first per group" without window-function lowering
    • take_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)
  • Decs lane for join_count stays absent — would need a Dealer [decs_template] + nested-archetype hash index. TODO referenced in the bench file and results.md.
  • Adds benchmarks/sql/results.md with two tables (INTERP + JIT) from master 1c8ff9119, columns labeled SQL / Array / Decs (user-facing — drops the m1/m3f/m4 jargon), plus per-gap footnotes that quote each .das source comment verbatim.
  • Fills in benchmarks/README.md sql/ 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 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 with standard label / seealso / download blocks; added to the language toctree after 54_glob.

Commit 2 also — linq-fold patterns reference (doc/source/reference/linq_fold_patterns.rst):

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 chains that drop to fold_linq_default. Linked from the reference toctree and from the handmade module-linq_fold.rst "See also" block (which feeds the generated stdlib/generated/linq_fold.rst).

Follow-up TODOs spawned (none block this PR)

  1. sqlite_linq distinct/distinct_by lowering — surfaced by distinct_by_count probe.
  2. sqlite_linq window-function lowering — surfaced by groupby_first probe (would enable ROW_NUMBER() OVER (PARTITION BY ...)).
  3. sqlite_linq expression-key support in _group_by — surfaced by groupby_select_sum probe.
  4. decs join / cross-archetype lookup machinery in plan_join — surfaced by join_count decs-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.
  • INTERP bench reproduces the headline numbers in results.md (sort_first m4=13.4, m3f=11.0).
  • JIT bench completes with 0 new failures (requires rebuilt bin/daslanghost_jit_triple was added recently).
  • bin/daslang tutorials/language/55_linq_decs.das exits 0 with the expected print output.
  • Clean Sphinx build: rm -rf doc/sphinx-build site/doc && sphinx-build -b html -d doc/sphinx-build doc/source site/docbuild succeeded. with no new warnings vs master.
  • Generated doc/source/stdlib/generated/linq_fold.rst after bin/daslang doc/reflections/das2rst.das contains the :doc: link to /reference/linq_fold_patterns.

🤖 Generated with Claude Code

borisbat and others added 2 commits May 23, 2026 17:36
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>
Copilot AI review requested due to automatic review settings May 24, 2026 00:37
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 m3 lane across SQL benches, refresh “keep-out” comments with concrete _sql errors, backfill join_count SQL lane, and add benchmarks/sql/results.md + expand benchmarks/README.md.
  • Tutorials: add tutorials/language/55_linq_decs.das and its rendered RST page, and link it into the tutorials toctree.
  • Reference docs: add linq_fold_patterns.rst and link it from the reference index and module-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.

Comment thread tutorials/language/55_linq_decs.das
Comment thread doc/source/reference/tutorials/55_linq_decs.rst
Comment thread doc/source/reference/linq_fold_patterns.rst Outdated
Comment thread doc/source/reference/linq_fold_patterns.rst
Comment thread benchmarks/README.md Outdated
Comment thread benchmarks/sql/results.md Outdated
- 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>
@borisbat borisbat merged commit 30021f1 into master May 24, 2026
30 checks passed
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>
@borisbat borisbat deleted the bbatkin/bench-sql-cleanup-tutorials-patterns-doc branch May 30, 2026 15:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants