Skip to content

[codex] Make array iterators lazy - #3747

Merged
aaronvg merged 5 commits into
canaryfrom
codex/lazy-array-iterators
Jun 12, 2026
Merged

aaronvg merged 5 commits into
canaryfrom
codex/lazy-array-iterators

Conversation

@aaronvg

@aaronvg aaronvg commented Jun 11, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • make baml.iter.ArrayIterator keep the source array instead of copying with slice
  • remove array-level iterator-only helpers so eager array methods stay array-returning and lazy helpers live on Iterator
  • add baml_src coverage for eager array filter().map() without collect(), lazy .iter().filter().map().collect(), and iterators seeing source-array mutations after creation

Validation

  • INSTA_UPDATE=always cargo insta test --test-runner nextest -p baml_tests --test baml_src -- bytecode
  • cargo nextest run -p baml_tests --test baml_src
  • git diff --check

Note

Medium Risk
Breaking change to the standard library Array API and iterator semantics (live array vs snapshot); core language/stdlib behavior with broad test updates but user code calling removed methods will fail at compile time.

Overview
Arrays no longer expose iterator convenience methods (filter_map, step_by, chain, peekable, collect, count). Lazy chaining uses array.iter() and methods on baml.iter.Iterator instead; eager filter/map still return arrays.

ArrayIterator.new holds the source array instead of slice(0, length), so iteration is lazy and sees later mutations (e.g. push after creating an iterator). The blanket Iterable impl for T[] in iter.baml is unchanged in spirit but now wires through that non-copying constructor.

Tests and compiler snapshots are updated for the new call pattern, with added coverage for eager filter().map(), lazy .iter()…collect(), and mutation visibility.

Reviewed by Cursor Bugbot for commit 1a8c7e6. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • Refactor

    • Array values no longer expose certain direct iterator convenience methods; iteration now uses an explicit iterator adapter and access pattern.
    • Iterator initialization optimized to avoid unnecessary cloning and reduce overhead.
  • Tests

    • Existing iterator tests updated to the new iteration pattern; new tests added covering eager vs lazy array-backed iteration and mutation semantics.

@vercel

vercel Bot commented Jun 11, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
beps Ready Ready Preview, Comment Jun 11, 2026 11:55pm
promptfiddle Ready Ready Preview, Comment Jun 11, 2026 11:55pm
promptfiddle2 Ready Ready Preview, Comment Jun 11, 2026 11:55pm

Request Review

@coderabbitai

coderabbitai Bot commented Jun 11, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Array had its convenience iterator methods removed; callers are migrated to baml.iter.Iterable.iter(). ArrayIterator now stores the original array (no clone), and tests are updated/added to validate eager and lazy iterator behaviors and the new adapter usage.

Changes

Iterator API Refactoring

Layer / File(s) Summary
Remove Array iterator declarations
baml_language/crates/baml_builtins2/baml_std/baml/containers.baml
Removed filter_map, step_by, chain, peekable, collect, and count method declarations from class Array<T>.
ArrayIterator stores source array
baml_language/crates/baml_builtins2/baml_std/baml/ns_iter/iter.baml
ArrayIterator<T>.new now stores the provided arr directly (no slice clone), with idx: 0, so iterators reference the original array.
Migrate tests to .iter() and add iterator cases
baml_language/crates/baml_tests/baml_src/ns_iter/iter.baml, baml_language/crates/baml_tests/baml_src/ns_iter_impl_generics_only/*
Update fluent-API tests to call .iter() on arrays; add three tests covering eager filter+map without collect, lazy iteration over a mutated source (with predicate call counting), and lazy filter_map(...).collect(); adjust fixtures to construct ArrayIterator directly and remove the implements<T> Iterable<T, never> for T[] block.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • BoundaryML/baml#3705: Overlapping work that added/remodeled array iterator adapter methods and is directly related to the API surface changes here.

Poem

🐰 I hopped through arrays and found,
The iterator moved off the ground.
Adapters call and arrays stay,
Lazy hops now lead the way.
Tests applaud the new parade.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main objective of the PR: making array iterators lazy by changing how ArrayIterator stores the source array.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/lazy-array-iterators

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@vercel
vercel Bot temporarily deployed to Preview – beps June 11, 2026 22:17 Inactive
@github-actions

github-actions Bot commented Jun 11, 2026 •

Copy link
Copy Markdown

⏭️ Performance benchmarks were skipped

Perf benchmarks (CodSpeed) are opt-in on pull requests — they no longer run on every push. They always run automatically after merge to canary/main.

To run them on this PR, do any of the following, then push a commit (or re-run CI):

  • Add RUN_CODSPEED=1 to the PR description, or
  • Include run-perf or /perf in the PR title or any commit message.

@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 11, 2026 22:22 Inactive
@aaronvg
aaronvg marked this pull request as ready for review June 11, 2026 22:27
@github-actions

Copy link
Copy Markdown

No description provided.

@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 11, 2026 22:31 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 11, 2026 22:32 Inactive
@aaronvg
aaronvg enabled auto-merge June 11, 2026 22:35
@aaronvg
aaronvg disabled auto-merge June 11, 2026 22:35
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 11, 2026 22:38 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 11, 2026 22:45 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 11, 2026 22:50 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 11, 2026 23:00 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 11, 2026 23:04 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 11, 2026 23:18 Inactive
@vercel
vercel Bot temporarily deployed to Preview – beps June 11, 2026 23:39 Inactive
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle2 June 11, 2026 23:44 Inactive
@aaronvg
aaronvg added this pull request to the merge queue Jun 11, 2026
@vercel
vercel Bot temporarily deployed to Preview – promptfiddle June 11, 2026 23:55 Inactive
Merged via the queue into canary with commit 725edd0 Jun 12, 2026
52 checks passed
@aaronvg
aaronvg deleted the codex/lazy-array-iterators branch June 12, 2026 00:05
meefs pushed a commit to meefs/baml that referenced this pull request Jun 12, 2026
… + live for-loop tests (BoundaryML#3749)

## Summary

Follow-ups to BoundaryML#3747 (lazy array iterators):

- **Fix nullable-element early termination.** `ArrayIterator.next`
matched `arr.at(idx)` against `null` to detect the end of iteration, so
an array of nullable `T` containing a `null` element stopped iterating
at the first `null`. It now bounds-checks by index, so stored `null`
elements are yielded. This was pre-existing, but live iterators flowing
through more code paths (including every `for` loop) made it likelier to
bite.
- **Add eager `Array.filter_map`.** Eager `filter`/`map` return arrays,
but `filter_map` only existed via `.iter().filter_map(fn).collect()`.
This adds an eager array-returning form, implemented in BAML and
mirroring `for_each`'s snapshot-via-`slice` idiom; the lazy version
remains on `Iterator`.
- **Pin `for`-loop live-view semantics.** BoundaryML#3747 made `ArrayIterator`
hold the source array instead of a snapshot, and `for` loops lower
through `Iterable.iter()`, so loops now see mid-loop mutations. That was
only tested via explicit `.iter()`; this adds tests pinning that a
`push` mid-loop is visited and a `pop` mid-loop terminates cleanly.

## Validation

- `INSTA_UPDATE=always cargo insta test --test-runner nextest -p
baml_tests -p baml_cli`
- `cargo nextest run -p baml_tests --test baml_src` (2 passed)
- `cargo nextest run -p baml_tests --lib --test bytecode_format` (1599
passed)
- `cargo nextest run -p baml_cli describe` (83 passed)
- `git diff --check`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes core iterator/`for`-loop semantics for nullable element types
and documents live-array mutation during iteration; incorrect bounds
logic could affect many call sites.
> 
> **Overview**
> Fixes **array iteration** when elements can be `null`:
`ArrayIterator.next` now ends on an index past the length instead of
treating `at()` returning `null` as exhaustion, so nullable arrays yield
every slot including stored `null`s.
> 
> Adds **eager `Array.filter_map`**, building a new array via a
`slice`-bounded `for` loop (same snapshot pattern as `for_each`); lazy
`iter().filter_map` is unchanged.
> 
> New **stdlib tests** lock in `for`-loop behavior over live array views
(push mid-loop is seen; repeated pop shortens iteration), eager
`filter_map`, and nullable-element iteration/`count`.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
fc9a51f. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **New Features**
* Added `filter_map` method for arrays to combine mapping and filtering
operations in a single operation.

* **Bug Fixes**
* Fixed iterator behavior to correctly yield null elements in arrays
with nullable types, rather than treating them as iteration endpoints.

* **Tests**
* Added comprehensive iterator test coverage for array mutations and
nullable element handling.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Co-authored-by: Claude Fable 5 <[email protected]>

This branch was previously deployed

3 inactive deployments
Preview – promptfiddle — 1a8c7e64 Deployed Jun 11, 2026 by vercel[bot]
Preview – promptfiddle2 — 1a8c7e64 Deployed Jun 11, 2026 by vercel[bot]
Preview – beps — 1a8c7e64 Deployed Jun 11, 2026 by vercel[bot]
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.

1 participant