-
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: cmp and ops reform #439
Conversation
} | ||
|
||
// Recovering by-ref semantics: | ||
impl<'a, 'b> Add<&'a str> for &'b String { |
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.
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?
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. |
outlined above: | ||
|
||
```rust | ||
pub trait Index<Idx> { |
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.
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]
?
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. |
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
|
derp |
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?) |
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. |
|
||
where | ||
|
||
struct Range<Idx>(Idx, Idx); |
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.
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.
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.
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
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.
@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.
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.
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.
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.
Which version is overengineering? (It seems to me that any of them could be regarded as overengineering depending on your perspective.)
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.
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.
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.
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.
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.
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.
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`. |
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.
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).
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.
I would say we should either have deref coercions or keep []
. &*v
is very ugly from an aesthetic point of view.
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.
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 []
.
Could you clarify what this means for the symmetry of operators please? Taking |
+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. |
```rust | ||
pub trait Deref { | ||
type Sized? Result; | ||
fn deref<'a>(&'a self) -> &'a Result; |
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.
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.
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.
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.
rust-lang/rust#18486 removes the autoref magic from binary operators. In other words,
rust-lang/rust#18486 adds @nikomatsakis can confirm/elaborate |
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. |
# Summary | ||
|
||
This RFC proposes a number of design improvements to the `cmp` and | ||
`ord` modules in preparation for 1.0. The impetus for these |
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.
typo ord
, should be ops
(same typo is in intro comment)
|
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 |
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 |
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.
“These” here only refers to the Fn*
traits, not all the traits mentioned in the RFC, right?
Isn’t the range notation ambiguous with the array repeat syntax? That is, |
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 |
@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. |
cc rust-lang/rust#9879, some old bikeshed about changing |
A straightforward fix would be to just use |
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 |
I've filed an amendment to deal with the grammar ambiguity, after some internal discussion. |
This patch marks `PartialEq`, `Eq`, `PartialOrd`, and `Ord` as `#[stable]`, as well as the majorify of manual implementaitons of these traits. The traits match the [reform RFC](rust-lang/rfcs#439). Along the way, two changes are made: * The recently-added type parameters for `Ord` and `Eq` are removed. These were mistakenly added while adding them to `PartialOrd` and `PartialEq`, but they don't make sense given the laws that are required for (and use cases for) `Ord` and `Eq`. * More explicit laws are added for `PartialEq` and `PartialOrd`, connecting them to their associated mathematical concepts. In the future, many of the impls should be generalized; see since generalizing later is not a breaking change. [breaking-change]
This patch marks `PartialEq`, `Eq`, `PartialOrd`, and `Ord` as `#[stable]`, as well as the majorify of manual implementaitons of these traits. The traits match the [reform RFC](rust-lang/rfcs#439). In the future, many of the impls should be generalized; see rust-lang#20063. However, there is no problem stabilizing the less general impls, since generalizing later is not a breaking change. r? @alexcrichton
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. |
To expand on that: I believe implementations of Meanwhile, we can't depend on
|
@eddyb @arthurprs There is discussion of the |
This patch marks `PartialEq`, `Eq`, `PartialOrd`, and `Ord` as `#[stable]`, as well as the majorify of manual implementaitons of these traits. The traits match the [reform RFC](rust-lang/rfcs#439). Along the way, two changes are made: * The recently-added type parameters for `Ord` and `Eq` are removed. These were mistakenly added while adding them to `PartialOrd` and `PartialEq`, but they don't make sense given the laws that are required for (and use cases for) `Ord` and `Eq`. * More explicit laws are added for `PartialEq` and `PartialOrd`, connecting them to their associated mathematical concepts. In the future, many of the impls should be generalized; see since generalizing later is not a breaking change. [breaking-change]
Some languages are able to do point-to-point vectorial comparisons:
Such overloading would be possible, for example, if trait
In whatever case, is there an RFC aimed at enabling point-to-point vector comparisons (or even more general comparisons such as functional point-to-point comparisons, etc.)? |
This is absolutely the worst place to ask this question. This RFC has not received any activity since 2015, and people who started following the project in the past nine years will not notice it. You should prefer asking these questions via internals or zulip, not here. |
This RFC proposes a number of design improvements to the
cmp
andops
modules 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.
IndexSet
to better support maps.Rendered