refactor(builtin): default end to self.length() on view constructors - #4012
Open
Yu-zh wants to merge 1 commit into
Open
refactor(builtin): default end to self.length() on view constructors#4012Yu-zh wants to merge 1 commit into
end to self.length() on view constructors#4012Yu-zh wants to merge 1 commit into
Conversation
Collaborator
Coverage Report for CI Build 5891Coverage decreased (-0.02%) to 90.447%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
Yu-zh
force-pushed
the
Yu-zh/view-default-end-arg
branch
from
August 12, 2026 08:25
b6f4e9b to
a865718
Compare
The view/slice constructors all declared `end? : Int` (no default) and then
re-derived the missing case in the body, each with its own idiom:
let end = match end { Some(end) | (None with end = len) => end }
let end_offset = if end_offset is Some(o) { o } else { self.length() }
match end { None => fixed[start:], Some(e) => fixed[start:e] }
Since MoonBit default-argument expressions can reference earlier parameters,
`end? : Int = self.length()` says the same thing in the signature, so the body
works with a plain `Int` and the unwrapping disappears. 26 functions across
`ArrayView`, `MutArrayView`, `BytesView`, `StringView`, `ReadOnlyArray` and
`UninitializedArray`.
Behavior is unchanged everywhere:
- For the `len`-based cases the default is literally the `len` the body
computed.
- `StringView::{get_view,sub}` used `self.end()` for the `None` branch;
`self.start() + self.length()` is the same value because
`StringView::length() == end() - start()`.
- `{String,StringView}::clamped_view` clamped the `Some` branch into
`[0, len]`; `self.length()` is already in range, so it clamps to itself.
- `ReadOnlyArray::view` fell back to `fixed[start:]`, whose own default is the
fixed array's length, and `ReadOnlyArray::length()` is defined as exactly
that.
`moon info` reports no `.mbti` change — the generated interface does not encode
default values — so this is not a source- or interface-breaking change for
downstream users.
Not converted: `Iter::view` genuinely needs `Option` (an iterator has no length,
and `None` selects a `drop`-only fast path), and `{Array,FixedArray}::fill` are
range-taking but not view constructors.
bobzhang
force-pushed
the
Yu-zh/view-default-end-arg
branch
from
August 12, 2026 10:40
a865718 to
f299681
Compare
bobzhang
reviewed
Aug 12, 2026
| let end = match end { | ||
| Some(end) | (None with end = len) => end | ||
| } | ||
| guard start >= 0 && start <= end && end <= len else { |
Contributor
There was a problem hiding this comment.
what's the motivation? for easy inlining?
Note this could introduce some duplicated computation
Collaborator
Author
There was a problem hiding this comment.
duplicated computations are caused by the wrappers and I plan to inline them as well (if the size of default values are reasonably small)
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.
What
The view/slice constructors in
builtinall declaredend? : Intwith no default and then re-derived the missing case inside the body, each with a slightly different idiom:A default-argument expression can reference an earlier parameter, so
end? : Int = self.length()states the same thing in the signature. The body then works with a plainIntand the unwrapping goes away — 26 functions, −62 lines net.Covered types:
ArrayView,MutArrayView,BytesView,StringView,ReadOnlyArray,UninitializedArray(plus the deprecatedString::substring).Why it is behavior-preserving
len-based cases — the default is literally thelenthe body already computed.StringView::{get_view,sub}usedself.end()in theNonebranch.self.start() + self.length()is the same value, sinceStringView::length()is defined asend() - start().{String,StringView}::clamped_viewclamped theSomebranch into[0, len].self.length()is already in range, so it clamps to itself.ReadOnlyArray::viewfell back tofixed[start:], whose own default is the fixed array's length — andReadOnlyArray::length()is defined as exactly that.moon infoproduces no.mbtidiff: the generated interface renders both forms asend? : Int, so this is not a source- or interface-breaking change for downstream users.Not converted
Iter::viewgenuinely needs theOption: an iterator has no length, andNoneselects adrop-only fast path thatSomecannot express.{Array,FixedArray}::filltake a range but are not view constructors, so they are left alone here.Verification