-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC for inclusive ranges with ... #1192
Merged
Merged
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
- Feature Name: inclusive_range_syntax | ||
- Start Date: 2015-07-07 | ||
- RFC PR: (leave this empty) | ||
- Rust Issue: (leave this empty) | ||
|
||
# Summary | ||
|
||
Allow a `x...y` expression to create an inclusive range. | ||
|
||
# Motivation | ||
|
||
There are several use-cases for inclusive ranges, that semantically | ||
include both end-points. For example, iterating from `0_u8` up to and | ||
including some number `n` can be done via `for _ in 0..n + 1` at the | ||
moment, but this will fail if `n` is `255`. Furthermore, some iterable | ||
things only have a successor operation that is sometimes sensible, | ||
e.g., `'a'..'{'` is equivalent to the inclusive range `'a'...'z'`: | ||
there's absolutely no reason that `{` is after `z` other than a quirk | ||
of the representation. | ||
|
||
The `...` syntax mirrors the current `..` used for exclusive ranges: | ||
more dots means more elements. | ||
|
||
# Detailed design | ||
|
||
`std::ops` defines | ||
|
||
```rust | ||
pub struct RangeInclusive<T> { | ||
pub start: T, | ||
pub end: T, | ||
pub finished: bool, | ||
} | ||
|
||
pub struct RangeToInclusive<T> { | ||
pub end: T, | ||
} | ||
``` | ||
|
||
Writing `a...b` in an expression desugars to `std::ops::RangeInclusive | ||
{ start: a, end: b, finished: false }`. Writing `...b` in an | ||
expression desugars to `std::ops::RangeToInclusive { end: b }`. | ||
|
||
`RangeInclusive` implements the standard traits (`Clone`, `Debug` | ||
etc.), and implements `Iterator`. The `finished` field is to allow the | ||
`Iterator` implementation to work without hacks (see Alternatives). | ||
|
||
The use of `...` in a pattern remains as testing for inclusion | ||
within that range, *not* a struct match. | ||
|
||
The author cannot forsee problems with breaking backward | ||
compatibility. In particular, one tokenisation of syntax like `1...` | ||
now would be `1. ..` i.e. a floating point number on the left, | ||
however, fortunately, it is actually tokenised like `1 ...`, and is | ||
hence an error with the current compiler. | ||
|
||
# Drawbacks | ||
|
||
There's a mismatch between pattern-`...` and expression-`...`, in that | ||
the former doesn't undergo the same desugaring as the | ||
latter. (Although they represent essentially the same thing | ||
semantically.) | ||
|
||
The `...` vs. `..` distinction is the exact inversion of Ruby's syntax. | ||
|
||
Having an extra field in a language-level desugaring, catering to one | ||
library use-case is a little non-"hygienic". It is especially strange | ||
that the field isn't consistent across the different `...` | ||
desugarings. | ||
|
||
# Alternatives | ||
|
||
An alternate syntax could be used, like | ||
`..=`. [There has been discussion][discuss], but there wasn't a clear | ||
winner. | ||
|
||
[discuss]: https://internals.rust-lang.org/t/vs-for-inclusive-ranges/1539 | ||
|
||
This RFC doesn't propose non-double-ended syntax, like `a...`, `...b` | ||
or `...` since it isn't clear that this is so useful. Maybe it is. | ||
|
||
The `finished` field could be omitted, leaving two options: | ||
|
||
- `a...b` only implements `IntoIterator`, not `Iterator`, by | ||
converting to a different type that does have the field. However, | ||
this means that `a...b` behaves differently to `a..b`, so | ||
`(a...b).map(|x| ...)` doesn't work (the `..` version of that is | ||
used reasonably often, in the author's experience) | ||
- `a...b` can implement `Iterator` for types that can be stepped | ||
backwards: the only case that is problematic things cases like | ||
`x...255u8` where the endpoint is the last value in the type's | ||
range. A naive implementation that just steps `x` and compares | ||
against the second value will never terminate: it will yield 254 | ||
(final state: `255...255`), 255 (final state: `0...255`), 0 (final | ||
state: `1...255`). I.e. it will wrap around because it has no way to | ||
detect whether 255 has been yielded or not. However, implementations | ||
of `Iterator` can detect cases like that, and, after yielding `255`, | ||
backwards-step the second piece of state to `255...254`. | ||
|
||
This means that `a...b` can only implement `Iterator` for types that | ||
can be stepped backwards, which isn't always guaranteed, e.g. types | ||
might not have a unique predecessor (walking along a DAG). | ||
|
||
# Unresolved questions | ||
|
||
None so far. |
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, it now does.