Skip to content

[Repo Assist] refactor: simplify lengthBy and lengthBeforeMax using while!#352

Draft
github-actions[bot] wants to merge 2 commits intomainfrom
repo-assist/improve-length-clarity-20260317-57345acc176658a5
Draft

[Repo Assist] refactor: simplify lengthBy and lengthBeforeMax using while!#352
github-actions[bot] wants to merge 2 commits intomainfrom
repo-assist/improve-length-clarity-20260317-57345acc176658a5

Conversation

@github-actions
Copy link
Contributor

🤖 This is an automated pull request from Repo Assist.

Summary

Simplify lengthBy and lengthBeforeMax by replacing the pre-loop MoveNextAsync + mutable go pattern with idiomatic while! loops.

Before

let mutable go = true
let mutable i = 0
let! step = e.MoveNextAsync()   // unconditional pre-loop advance
go <- step

match predicate with
| None ->
    while go do
        let! step = e.MoveNextAsync()
        i <- i + 1   // obscure ordering: count happens after advancing
        go <- step
| ...

After

let mutable i = 0

match predicate with
| None ->
    while! e.MoveNextAsync() do
        i <- i + 1
| ...

The while! e.MoveNextAsync() do idiom is the standard pattern used throughout the rest of this codebase (e.g. maxMin, sum, average, contains). Applying it here brings lengthBy in line with those functions and removes the confusing "count before moving" comment.

Improved semantics for lengthBeforeMax

The old implementation had an accidental "read-ahead by 1": it called MoveNextAsync once unconditionally before the loop, meaning TaskSeq.lengthOrMax 5 on a longer sequence would evaluate 6 elements instead of 5, and TaskSeq.lengthOrMax 0 would evaluate 1 element instead of 0.

The new implementation is cleaner and evaluates exactly min(length, max) elements — no read-ahead:

while go && i < max do
    let! hasMore = e.MoveNextAsync()
    if hasMore then i <- i + 1 else go <- false

Three tests in TaskSeq.Length.Tests.fs that explicitly asserted the old N+1 / 1 read-ahead counts have been updated to assert the correct N / 0 values, with revised test names and comments.

Test Status

Build: ✅ succeeded (0 warnings, 0 errors)
Tests: ✅ 5013 passed, 2 skipped (infrastructure), 0 failed

Branch: repo-assist/improve-length-clarity-20260317

Generated by Repo Assist ·

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@346204513ecfa08b81566450d7d599556807389f

Replace the pattern of:
  - one unconditional MoveNextAsync call before the loop
  - a mutable 'go' flag
  - manual go/step tracking

...with the simpler 'while! e.MoveNextAsync() do' form.

For lengthBy (all three predicate variants), the new implementation is cleaner
and reads more naturally: iterate over elements, count those that match.

For lengthBeforeMax, the new implementation advances the enumerator inside the
loop body and guards with 'go && i < max', eliminating the pre-loop advance.
A beneficial side effect: the old implementation had a read-ahead of 1 (an
extra MoveNextAsync call before the loop), which meant lengthOrMax 5 on a
10-element source would evaluate 6 elements instead of 5, and lengthOrMax 0
would still evaluate the first element.  The new implementation has no
read-ahead, so lengthOrMax N evaluates exactly N elements as expected.

Tests updated to reflect the improved (no read-ahead) behaviour, replacing
the N+1 and 1 assertions with the correct N and 0.

All 5013 existing tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants