Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upRFC: cmp and ops reform #439
Conversation
japaric
reviewed
Nov 4, 2014
| } | ||
| // Recovering by-ref semantics: | ||
| impl<'a, 'b> Add<&'a str> for &'b String { |
This comment has been minimized.
This comment has been minimized.
japaric
Nov 4, 2014
Member
Shouldn't Self be String (in which case, this would be append) or &'b str (I thought we preferred &str over &String were possible) here?
Kimundi
reviewed
Nov 4, 2014
| `&` for the operands, which means that the ownership semantics when | ||
| using these operators is much more clear. | ||
|
|
||
| Fortunately, there is no loss in expressiveness, since you can always |
This comment has been minimized.
This comment has been minimized.
Kimundi
Nov 4, 2014
Member
Does this assume that operators autoref their arguments? Eg, if I implement Add for &MyType, would I have to write &mytype + &mytype, or would mytype + mytype work?
This comment has been minimized.
This comment has been minimized.
japaric
Nov 4, 2014
Member
I think rust-lang/rust#18486 already removes the autoref magic, so you'll have to type &mytype + &mytype
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Huge +1 from me, especially with the stuff about merging index and slicing. Having them implemented as the same trait via multidispatch and a range operator makes stuff so much more modular. |
japaric
reviewed
Nov 4, 2014
| outlined above: | ||
|
|
||
| ```rust | ||
| pub trait Index<Idx> { |
This comment has been minimized.
This comment has been minimized.
japaric
Nov 4, 2014
Member
Shouldn't be for Sized?, otherwise we won't be able to implement it for [T].
Also, are we going to remove the built-in indexing support for slices (i.e. slice[0] works but [T]/&[T] doesn't implement the Index trait), and replace it with impl Index<uint> for [T]?
eddyb
reviewed
Nov 4, 2014
| because the refactored design is more modular. | ||
|
|
||
| What about `v[]` notation? The proposal is to desugar this to | ||
| `v[FullRange]` where `struct FullRange;`. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
japaric
Nov 4, 2014
Member
Since Deref would have no input type parameter with this RFC, that means that &*vec/&*string would unambigiously produce &[T]/&str, so we'll end with two sugary ways to do the same thing. I think we should consider dropping this []/[..] notation.
This comment has been minimized.
This comment has been minimized.
japaric
reviewed
Nov 4, 2014
| also opens the door to other uses of the range notation: | ||
|
|
||
| ``` | ||
| for x in 1..100 { ... } |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
huonw
Nov 4, 2014
Member
I'm very slightly concerned about this, because many other languages with syntax like this have the range inclusive. I do think the benefits of the generic range are better though.
This comment has been minimized.
This comment has been minimized.
aturon
Nov 4, 2014
Author
Member
Yes. This really forces us to revisit the .. and ... tradeoff, which is not a bad thing.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
lifthrasiir
Nov 6, 2014
Contributor
Is the Range inherently mutable? Otherwise it cannot be usable as an Iterator.
This comment has been minimized.
This comment has been minimized.
huonw
Nov 6, 2014
Member
Sure, it is essentially just struct Range<T> { start: T, stop: T }, nothing fancy that stops a theoretical implementation of Iterator (which is what the line here would require).
This comment has been minimized.
This comment has been minimized.
SimonSapin
Nov 20, 2014
Contributor
So is the range notation in all expression contexts part of this RFC, or something that could be added later? Is there no grammar ambiguity with <expr>.., ..<expr>, and <expr>..<expr> all being a valid <expr>?
sfackler
reviewed
Nov 4, 2014
| ```rust | ||
| pub trait IndexSet<Idx> { | ||
| type Val; | ||
| fn index_mut<'a>(&'a mut self, index: Idx, val: Val); |
This comment has been minimized.
This comment has been minimized.
sfackler
reviewed
Nov 4, 2014
| pub trait Eq<Rhs = Self>: PartialEq<Rhs> {} | ||
| pub trait PartialOrd<Rhs = Self>: PartialEq<Rhs> { |
This comment has been minimized.
This comment has been minimized.
sfackler
Nov 4, 2014
Member
Can we also nail down what constraints (if any) we want to state that implementations of PartialOrd need to maintain?
aturon
added some commits
Nov 4, 2014
This comment has been minimized.
This comment has been minimized.
|
I've pushed an update addressing most of the typos/questions people had so far. @sfackler, yes, this RFC is a good opportunity to nail down those invariants. I'll add that shortly. |
This comment has been minimized.
This comment has been minimized.
|
On Tue, Nov 04, 2014 at 12:01:29PM -0800, Aaron Turon wrote:
@aturon: Just for the record, here are some things I noted, some of
|
This comment has been minimized.
This comment has been minimized.
|
derp |
This comment has been minimized.
This comment has been minimized.
I'm in favor of
Seems reasonable. Of course we can add this backwards-compatibly. Somewhat subtle notation, but it's hard to do better.
Yes, this RFC uses "exemplars" throughout rather than exhaustively listing all the traits. In any case the plan laid out here is admittedly a bit sketchy on the details (i.e., are stability attributes enough to do this staging?) |
This comment has been minimized.
This comment has been minimized.
|
Took me a bit to wrap my head around all the consequences, but now it all makes sense to me. +1, removes a lot of magic. |
huonw
reviewed
Nov 4, 2014
| where | ||
| struct Range<Idx>(Idx, Idx); |
This comment has been minimized.
This comment has been minimized.
huonw
Nov 4, 2014
Member
Could these be unified as:
struct Range<Idx> {
low: Option<Idx>,
high: Option<Idx>
}and then i..j is (Some, Some), i.. is (Some, None) etc.? Downsides I can think of are losing the ability to be specific about exactly what sort of slicing works, but benefits include not forgetting to implement one of them.
This comment has been minimized.
This comment has been minimized.
sfackler
Nov 4, 2014
Member
I wrote up a range type for rust-postgres here that's a bit more robust - with support for inclusive and exclusive bounds as well as the empty range. It's more than what's needed for this syntax, but if we're going to have the types, it might be worth making them more fleshed out: https://github.com/sfackler/rust-postgres/blob/master/src/types/range.rs
This comment has been minimized.
This comment has been minimized.
aturon
Nov 4, 2014
Author
Member
@huonw Right, that seems to be the tradeoff: for x in ..3 would be a panic rather than type error.
Still, probably worth it to do something like you're suggesting.
This comment has been minimized.
This comment has been minimized.
Gankro
Nov 4, 2014
Contributor
I'd rather not overengineer this much. I like that the separate types mean that the right impl statically dispatches, whereas the Option case requires runtime branching to "pick" the impl. Also as @aturon notes failing to impl a variant isn't a runtime error.
This comment has been minimized.
This comment has been minimized.
huonw
Nov 4, 2014
Member
Which version is overengineering? (It seems to me that any of them could be regarded as overengineering depending on your perspective.)
This comment has been minimized.
This comment has been minimized.
Gankro
Nov 4, 2014
Contributor
Inclusive/Exclusive range types seems like overkill to me here. Especially since the syntax to get something like (a, b] isn't clear.
The Options I could take or leave, save the possibility of static dispatch otherwise.
This comment has been minimized.
This comment has been minimized.
arcto
Nov 5, 2014
I'd rather see a type error than a runtime panic, in every instance possible. If ..3 isn't logically meaningful then let that be a type error. That's better for correctness and for performance.
This comment has been minimized.
This comment has been minimized.
huonw
Nov 5, 2014
Member
Encoding information in the type system is valuable, but we have to balance making things too hard/annoying to use with a huge pile of types.
nrc
assigned
aturon
Nov 5, 2014
nrc
reviewed
Nov 5, 2014
| language are likely to face quickly. | ||
|
|
||
| In the opinion of this RFC author, we should either keep `[]` | ||
| notation, or provide deref coercions so that you can just say `&v`. |
This comment has been minimized.
This comment has been minimized.
nrc
Nov 5, 2014
Member
I'm a big fan of &v now - I've been converting a bunch of [T, ..n] to &[T] and writing &v feels 'right'. I'd like to extend that to vecs. I think I would prefer to lose [] - I've already been confused by it a few times (an although I used to like [..] it is starting to look pretty ugly to me now).
This comment has been minimized.
This comment has been minimized.
brendanzab
Nov 5, 2014
Member
I would say we should either have deref coercions or keep []. &*v is very ugly from an aesthetic point of view.
This comment has been minimized.
This comment has been minimized.
aturon
Nov 5, 2014
Author
Member
It sounds like we should consider the deref coercions RFC. Perhaps if that's accepted before this one is discussed, I can change this RFC to drop [].
This comment has been minimized.
This comment has been minimized.
|
Could you clarify what this means for the symmetry of operators please? Taking |
This comment has been minimized.
This comment has been minimized.
|
+1 for me. Cuts down a great deal of sugar. I very much like the by-value operators - it's a shame that in using & we can't take advantage of Rust's efficient move-semantics for certain types. |
P1start
reviewed
Nov 5, 2014
| ```rust | ||
| pub trait Deref { | ||
| type Sized? Result; | ||
| fn deref<'a>(&'a self) -> &'a Result; |
This comment has been minimized.
This comment has been minimized.
P1start
Nov 5, 2014
Contributor
Has the option of changing this to fn deref(self) -> Result been considered? So all impl Deref for Bar { type Result = Foo; ... }s would be changed to impl<'a> Deref for &'a Bar { type Result = &'a Foo; ... }. The advantage of this is that Deref, DerefMut, and even the hypothetical DerefMove could all be combined into a single trait. The same transformation could happen to Index as well (and maybe even the Fn traits), although IndexSet would still be required for maps. Such a change to all those traits would probably require adjusting the existing compiler machinery that determines which trait to use to instead determine how (if at all) to auto-reference.
I feel that there’s got to be some reason why this isn’t feasible, but I can’t think of one, other than requiring some extra auto-referencing logic. All the other traits are being by-value-ified, which is great, so it would be nice if that could extend to every trait.
This comment has been minimized.
This comment has been minimized.
aturon
Nov 5, 2014
Author
Member
I'm not sure how feasible that would be. The compiler has a fair amount of special machinery for choosing between Deref and DerefMut, and similarly for the Index/IndexMut pair. @nikomatsakis or @pcwalton could probably say more.
P1start
reviewed
Nov 5, 2014
| ```rust | ||
| i..j ==> Range(i, j) | ||
| i.. ==> RangeFrom(i) | ||
| ..j ==> RangeTo(j) |
This comment has been minimized.
This comment has been minimized.
P1start
Nov 5, 2014
Contributor
Would these be able to be pattern-matched on, e.g., match 1..3 { 1..b => foo(), a..5 => bar(), _ => baz() }? If so, the distinction between .. and ... would be very subtle and potentially confusing. I think the best option would be to require using the desugared version, i.e., Range(a, b), in patterns.
This comment has been minimized.
This comment has been minimized.
tikue
Nov 11, 2014
I don't think this would work, because a..b means something different when pattern matching. It means you're matching against a single value in the range a..b.
This comment has been minimized.
This comment has been minimized.
P1start
Nov 11, 2014
Contributor
The syntax for ranges in patterns was changed to ... (with three dots, unlike the two dots used for ranges) recently, so it wouldn’t be ambiguous to the parser. An extra dot doing such a significant change would be quite confusing, though.
This comment has been minimized.
This comment has been minimized.
nikomatsakis
Nov 11, 2014
Contributor
On Mon, Nov 10, 2014 at 08:08:34PM -0800, P1start wrote:
The syntax for ranges in patterns was changed to
...(with three
dots, unlike the two dots used for ranges) recently, so it wouldn’t
be ambiguous to the parser. An extra dot doing such a significant
change would be quite confusing, though.
Note that, as far as the parser is concerned, there is no problem at
all: pattern and expression syntax are distinct. There is perhaps some
concern for human readers, where they might expect to destructure a
pattern rather than to apply the pattern. I personally think this is
not really a problem though.
This comment has been minimized.
This comment has been minimized.
rust-lang/rust#18486 removes the autoref magic from binary operators. In other words,
rust-lang/rust#18486 adds @nikomatsakis can confirm/elaborate |
This comment has been minimized.
This comment has been minimized.
ben0x539
commented
Nov 5, 2014
|
So generally, I'm fairly skeptical of providing operator overloading but designing it so using arithmetic operators works differently depending on whether the operands are primitives or not. The existing desugaring that adds a level of indirection is a lot more intuitive to me. I really don't understand the motivation of #118 is probably relevant. |
seanmonstar
reviewed
Nov 5, 2014
| # Summary | ||
|
|
||
| This RFC proposes a number of design improvements to the `cmp` and | ||
| `ord` modules in preparation for 1.0. The impetus for these |
This comment has been minimized.
This comment has been minimized.
kevinmehall
referenced this pull request
Nov 5, 2014
Closed
unifying slicing_syntax and range function #443
This comment has been minimized.
This comment has been minimized.
|
|
This comment has been minimized.
This comment has been minimized.
More precisely:
No. You only need
There's libnum, and I'm sure many other examples.
I'm not sure I understand this concern. The operators would always take their arguments by value. But in some cases those arguments might be
The broader point is that the by-ref semantics restrict the possible uses of the operators. Using by-value is more general, since you can always implement for references. And for non- Also, I'm not sure what you mean by "behave differently than arithmetic on primitives"? In general, the way that by-value parameters work varies depending on whether data is |
alexcrichton
merged commit f1848c0
into
rust-lang:master
Nov 20, 2014
alexcrichton
added a commit
that referenced
this pull request
Nov 20, 2014
This comment has been minimized.
This comment has been minimized.
SimonSapin
reviewed
Nov 20, 2014
| particular, the sugar for these traits requires writing all of these | ||
| types anyway. | ||
|
|
||
| These traits should *not* be exposed as `#[stable]` for 1.0, meaning |
This comment has been minimized.
This comment has been minimized.
SimonSapin
Nov 20, 2014
Contributor
“These” here only refers to the Fn* traits, not all the traits mentioned in the RFC, right?
This was referenced Nov 24, 2014
This comment has been minimized.
This comment has been minimized.
|
Isn’t the range notation ambiguous with the array repeat syntax? That is, |
This comment has been minimized.
This comment has been minimized.
|
Hm, that seems troublesome indeed, but could still be managed by some kind of special casing in the lexer. Could be either two ranges up to four, or four ranges up to four if |
This comment has been minimized.
This comment has been minimized.
|
@P1start Wow, good catch... I really wish we had a grammar! I'm still digesting this a bit to figure out a reasonable path forward here. But everyone reading this, feel free to toss out suggestions. |
This comment has been minimized.
This comment has been minimized.
|
cc rust-lang/rust#9879, some old bikeshed about changing |
This comment has been minimized.
This comment has been minimized.
|
A straightforward fix would be to just use |
This comment has been minimized.
This comment has been minimized.
|
On Wed, Nov 26, 2014 at 08:27:27AM -0800, Aaron Turon wrote:
Sigh. Yes. Amazing how hard it is to catch (in retrospect) obvious |
aturon
referenced this pull request
Dec 5, 2014
Closed
Amendment to RFC 439 for grammar ambiguity #498
This comment has been minimized.
This comment has been minimized.
|
I've filed an amendment to deal with the grammar ambiguity, after some internal discussion. |
nrc
referenced this pull request
Dec 6, 2014
Closed
Remove the `[]` notation for taking a whole slice. #491
aturon
added a commit
to aturon/rust
that referenced
this pull request
Dec 20, 2014
aturon
added a commit
to aturon/rust
that referenced
this pull request
Dec 30, 2014
aturon
added a commit
to aturon/rust
that referenced
this pull request
Dec 30, 2014
aturon
added a commit
to aturon/rust
that referenced
this pull request
Dec 30, 2014
alexcrichton
added a commit
to alexcrichton/rust
that referenced
this pull request
Dec 31, 2014
bors
added a commit
to rust-lang/rust
that referenced
this pull request
Dec 31, 2014
This comment has been minimized.
This comment has been minimized.
arthurprs
commented
Mar 5, 2015
|
I'm trying to implement Ord to compare a struct Pair(K, V) against K This is what we have
but I (and the RFC) expected this
Is it a bug or oversight? What's the motivation? @eddyb suggested we made these traits unsafe. |
This comment has been minimized.
This comment has been minimized.
|
To expand on that: I believe implementations of Meanwhile, we can't depend on
|
This comment has been minimized.
This comment has been minimized.
|
@eddyb @arthurprs There is discussion of the |
aturon commentedNov 4, 2014
This RFC proposes a number of design improvements to the
cmpandopsmodules in preparation for 1.0. The impetus for theseimprovements, besides the need for stabilization, is that we've added
several important language features (like multidispatch) that greatly
impact the design. Highlights:
Equiv.traits are no longer needed.
IndexSetto better support maps.Rendered