Skip to content

poc(int): generic range via a Step trait - #3469

Closed
bobzhang wants to merge 2 commits into
mainfrom
poc/range-step-trait
Closed

poc(int): generic range via a Step trait#3469
bobzhang wants to merge 2 commits into
mainfrom
poc/range-step-trait

Conversation

@bobzhang

Copy link
Copy Markdown
Contributor

Summary

  • Proof-of-concept for a single generic range(start, end, step) that works across numeric types via a minimal Step trait (step_add / step_lt).
  • Shows MoonBit's trait-bounded generics (fn[T : Step] ...) are enough — we don't need "generics on traits" to unify Int::until / Int64::until / Double::until into one entry point.
  • Ergonomic upside at the call site: range(0, 10, 3) is shorter than (0).until(10, step=3) and avoids the 0. lexer trap where a bare integer literal followed by .method is parsed as a Double literal.

What's here

  • int/range_test.mbt (whitebox test): trait Step, impls for Int and Int64, and fn[T : Step] range(...) -> Iter[T], plus tests.
  • Intentionally NOT a production API. The file lives inside int/ only so the POC compiles against existing infra; a real home would be a dedicated range package.

Open design questions (for discussion)

  • Trait surface. Current POC has step_add + step_lt. To match Int::until fully we need negative step and inclusive=true. Options: add step_gt (or a single step_compare -> Int), or keep direction-specific methods.
  • Package layout. @range.range(0, 10, 3) vs @int.range(...) / @double.range(...) vs prelude export.
  • Migration. Deprecate Int::until / Int64::until / Double::until once the generic form lands, or keep them as thin shortcuts?
  • Richer API. If we introduce a Range[T] struct (not just Iter[T]), we can get contains, length, reverse, slice-indexing — at the cost of a new type in the surface area.

Test plan

  • moon test -p int passes locally (5256/5256).
  • Decide on trait shape before expanding impls to Double / UInt / Int64 / etc.
  • Decide on final package location before promoting out of POC.

🤖 Generated with Claude Code

Demonstrates that one `range(start, end, step)` can cover multiple
numeric types through a minimal `Step` trait (`step_add` / `step_lt`),
removing the need for per-type `Int::until` / `Int64::until` / etc.

Not a production API — just a feasibility check to open design
discussion. Lives as a whitebox test in `int/` for easy iteration;
real home would likely be a dedicated `range` package.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bobzhang
bobzhang marked this pull request as ready for review April 24, 2026 10:34

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

@coveralls

coveralls commented Apr 24, 2026

Copy link
Copy Markdown
Collaborator

Coverage Report for CI Build 3934

Coverage decreased (-0.02%) to 94.876%

Details

  • Coverage decreased (-0.02%) from the base build.
  • Patch coverage: 3 uncovered changes across 1 file (12 of 15 lines covered, 80.0%).
  • No coverage regressions found.

Uncovered Changes

File Changed Covered %
range/range.mbt 15 12 80.0%

Coverage Regressions

No coverage regressions found.


Coverage Stats

Coverage Status
Relevant Lines: 15594
Covered Lines: 14795
Line Coverage: 94.88%
Coverage Strength: 220040.8 hits per line

💛 - Coveralls

Introduces a new `@range` package with a `Step` trait (`Add + Compare +
Default`, plus a static `one()` for the default step) and a single
generic `range(start, end, step?, inclusive?) -> Iter[T]` function. One
entry point replaces the per-type `Int::until` / `Int64::until` /
`Double::until` forms and removes the `0.until(10)` lexer trap where
`0.` tokenizes as a `Double` literal.

Built-in `Step` impls for `Int`, `Int64`, `UInt`, `UInt64`, `Float`,
`Double`. User types opt in by implementing `Step`.

Semantics mirror `Int::until` exactly — zero-step yields an empty
iterator, negative step descends, inclusive=true includes `end`, and
overflow near the type's max is handled the same way. Existing
`::until` functions are untouched; deprecation is a follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bobzhang bobzhang closed this Apr 28, 2026
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