Skip to content
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

Merged
merged 4 commits into from Nov 20, 2014

Conversation

Projects
None yet
@aturon
Copy link
Member

aturon commented Nov 4, 2014

This RFC proposes a number of design improvements to the cmp and
ops modules in preparation for 1.0. The impetus for these
improvements, besides the need for stabilization, is that we've added
several important language features (like multidispatch) that greatly
impact the design. Highlights:

  • Make basic unary and binary operators work by value and use associated types.
  • Generalize comparison operators to work across different types; drop Equiv.
  • Refactor slice notation in favor of range notation so that special
    traits are no longer needed.
  • Add IndexSet to better support maps.
  • Clarify ownership semantics throughout.

Rendered

}
// Recovering by-ref semantics:
impl<'a, 'b> Add<&'a str> for &'b String {

This comment has been minimized.

@japaric

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?

`&` 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.

@Kimundi

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.

@japaric

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.

@aturon

aturon Nov 4, 2014

Author Member

I've added some clarifying text about this.

@Kimundi

This comment has been minimized.

Copy link
Member

Kimundi commented Nov 4, 2014

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> {

This comment has been minimized.

@japaric

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]?

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.

@eddyb

eddyb Nov 4, 2014

Member

Is it really needed at all? I recall @nikomatsakis not liking v[]/v[..].

This comment has been minimized.

@japaric

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.

@aturon

aturon Nov 4, 2014

Author Member

I added some thoughts about this to the "Alternatives" section.

also opens the door to other uses of the range notation:

```
for x in 1..100 { ... }

This comment has been minimized.

@japaric

japaric Nov 4, 2014

Member

yay, sugar!

This comment has been minimized.

@huonw

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.

@aturon

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.

@huonw

huonw Nov 6, 2014

Member

Another option is just not implementing iterator for a..b.

This comment has been minimized.

@lifthrasiir

lifthrasiir Nov 6, 2014

Contributor

Is the Range inherently mutable? Otherwise it cannot be usable as an Iterator.

This comment has been minimized.

@huonw

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.

@SimonSapin

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>?

```rust
pub trait IndexSet<Idx> {
type Val;
fn index_mut<'a>(&'a mut self, index: Idx, val: Val);

This comment has been minimized.

@sfackler

sfackler Nov 4, 2014

Member

s/index_mut/index_set/

pub trait Eq<Rhs = Self>: PartialEq<Rhs> {}
pub trait PartialOrd<Rhs = Self>: PartialEq<Rhs> {

This comment has been minimized.

@sfackler

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

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 4, 2014

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.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Nov 4, 2014

On Tue, Nov 04, 2014 at 12:01:29PM -0800, Aaron Turon wrote:

I've pushed an update addressing most of the typos/questions people had so far.

@aturon: Just for the record, here are some things I noted, some of
which I have communicated to you via IRC.

  • What happens if a type implements IndexMut but not IndexSet? We
    could potentially "fallback" but in general type inferencer works
    more smoothly if we can unilaterally use a trait and not have to do
    "probing". I'd prefer to just use IndexSet consistently.
    Conceivably we could make IndexMut : IndexSet, I don't know of any
    reason that you might implement IndexMut but not IndexSet since
    there is at worst a trivial desugaring.
  • Do we want to include expression forms of ... (inclusive range)?
  • There are of course three Fn traits. We should discuss the precise
    1.0 stability story there, but what you wrote is fine for now I think.
@Gankro

This comment has been minimized.

Copy link
Contributor

Gankro commented Nov 4, 2014

@nikomatsakis A Bitv can implement IndexSet, but not Index or IndexMut. You can't get references to its contents (since they're internally just bits).

derp

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 4, 2014

@nikomatsakis

What happens if a type implements IndexMut but not IndexSet? We
could potentially "fallback" but in general type inferencer works
more smoothly if we can unilaterally use a trait and not have to do
"probing". I'd prefer to just use IndexSet consistently.
Conceivably we could make IndexMut : IndexSet, I don't know of any
reason that you might implement IndexMut but not IndexSet since
there is at worst a trivial desugaring.

I'm in favor of IndexMut: IndexSet as the simplest way out of this question. Anyone see a problem with that approach?

Do we want to include expression forms of ... (inclusive range)?

Seems reasonable. Of course we can add this backwards-compatibly. Somewhat subtle notation, but it's hard to do better.

There are of course three Fn traits. We should discuss the precise
1.0 stability story there, but what you wrote is fine for now I think.

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?)

@Gankro

This comment has been minimized.

Copy link
Contributor

Gankro commented Nov 4, 2014

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);

This comment has been minimized.

@huonw

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.

@sfackler

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.

@aturon

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.

@Gankro

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.

@huonw

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.

@Gankro

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.

@arcto

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.

@huonw

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.

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.

@nrc

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.

@brendanzab

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.

@aturon

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 [].

@nrc

This comment has been minimized.

Copy link
Member

nrc commented Nov 5, 2014

Could you clarify what this means for the symmetry of operators please? Taking == as an example, if I write a == b will the coercion/autoref'ing applied to the operands be symmetric? After removing the [T, ..n] -> &[T] coercion, comparing slices is really ugly - e.g., if a and b are both [T, ..n] you have to write a == &b.

@brendanzab

This comment has been minimized.

Copy link
Member

brendanzab commented Nov 5, 2014

+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;

This comment has been minimized.

@P1start

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.

@aturon

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.

```rust
i..j ==> Range(i, j)
i.. ==> RangeFrom(i)
..j ==> RangeTo(j)

This comment has been minimized.

@P1start

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.

@tikue

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.

@P1start

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.

@nikomatsakis

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.

@japaric

This comment has been minimized.

Copy link
Member

japaric commented Nov 5, 2014

@nick29581

Taking == as an example, if I write a == b will the coercion/autoref'ing applied to the operands be symmetric?

rust-lang/rust#18486 removes the autoref magic from binary operators. In other words, a OP b (AIUI) desugars to OpTrait::op_method(&a, &b), i.e. it only works if impl OpTrait<B> for A, where a/b has type A/B.

After removing the [T, ..n] -> &[T] coercion, comparing slices is really ugly - e.g., if a and b are both [T, ..n] you have to write a == &b.

rust-lang/rust#18486 adds impl PartialEq for [T, ..N] up to N = 32, so a == b will work if a and b have types [T, ..N] and N <= 32.

@nikomatsakis can confirm/elaborate

@ben0x539

This comment has been minimized.

Copy link

ben0x539 commented Nov 5, 2014

So generally, a + b will potentially move from a and/or b? Does a += b still work (presumably in a = a + b, a is moved to the addition and then the variable cannot be used for the assignment anymore) [edit: apparently this already stopped working long ago, nevermind]? Are we going to ship impls for &int: Add<&int>, int: Add<&int> and &int: Add<int> etc.? Do Rust libraries offering arbitrary-sized integers or similar exist yet to which we can look for practical experience?

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 DList concatenation that is apparently supposed to behave differently than arithmetic on primitives but use the same syntax. What is the intended syntactical improvement there? let a = a + b; instead of a.append(b);?

#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

This comment has been minimized.

@seanmonstar

seanmonstar Nov 5, 2014

Contributor

typo ord, should be ops

(same typo is in intro comment)

@cmr

This comment has been minimized.

Copy link
Member

cmr commented Nov 5, 2014

IndexSet is very important to me because it allows me to nicely model write-only memory mapping, which is important for graphics APIs.

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 5, 2014

@ben0x539

So generally, a + b will potentially move from a and/or b?

More precisely: a + b will always move both a and b. But the moved values can be references in the case of non-Copy data (&matrix1 + &matrix2) and, for Copy data, you're moving a copy as per usual.

Are we going to ship impls for &int: Add<&int>, int: Add<&int> and &int: Add<int> etc.?

No. You only need int: Add<int>, because int is Copy. Same for the rest of the primitive types.

Do Rust libraries offering arbitrary-sized integers or similar exist yet to which we can look for practical experience?

There's libnum, and I'm sure many other examples.

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'm not sure I understand this concern. The operators would always take their arguments by value. But in some cases those arguments might be Copy data, e.g. primitive types, in which case passing by value entails copying. This is already the case in Rust generally.

I really don't understand the motivation of DList concatenation that is apparently supposed to behave differently than arithmetic on primitives but use the same syntax. What is the intended syntactical improvement there? let a = a + b; instead of a.append(b);?

DList is just one example where consuming a non-Copy value would make sense.

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-Copy operands, explicitly marking whether you are moving or passing by reference is usually helpful for reasoning about ownership locally (and is more consistent with fn arguments in general).

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 Copy or not (with the simple rule that Copy data moves a copy of the data), so this is just making the operators consistent with other parts of the language.

@alexcrichton alexcrichton merged commit f1848c0 into rust-lang:master Nov 20, 2014

alexcrichton added a commit that referenced this pull request Nov 20, 2014

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented 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.

@SimonSapin

SimonSapin Nov 20, 2014

Contributor

“These” here only refers to the Fn* traits, not all the traits mentioned in the RFC, right?

@P1start

This comment has been minimized.

Copy link
Contributor

P1start commented Nov 26, 2014

Isn’t the range notation ambiguous with the array repeat syntax? That is, [3u, ..4] could either be an array containing four threes, or an array containing one three and one range up to four. I guess the array notation could be changed to [3u, ...4] (which seems wrong, as ... generally represents an inclusive range in Rust, but would represent an exclusive range of indices), but that would rule out the possibility of inclusive range sugar.

@Kimundi

This comment has been minimized.

Copy link
Member

Kimundi commented Nov 26, 2014

Hm, that seems troublesome indeed, but could still be managed by some kind of special casing in the lexer.
However, the truly problematic example would be this: [..4, ..4]

Could be either two ranges up to four, or four ranges up to four if ..4 evaluates to a copyable type.

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Nov 26, 2014

@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.

@alexcrichton

This comment has been minimized.

Copy link
Member

alexcrichton commented Nov 26, 2014

cc rust-lang/rust#9879, some old bikeshed about changing [foo, ..N], although that may not be the route we want to take.

@glaebhoerl

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Nov 26, 2014

A straightforward fix would be to just use _..4 instead of ..4 for single-ended ranges (and likewise 4.._). Not very pretty though.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Nov 27, 2014

On Wed, Nov 26, 2014 at 08:27:27AM -0800, Aaron Turon wrote:

@P1start Wow, good catch... I really wish we had a grammar!

Sigh. Yes. Amazing how hard it is to catch (in retrospect) obvious
ambiguities!

@aturon

This comment has been minimized.

Copy link
Member Author

aturon commented Dec 5, 2014

I've filed an amendment to deal with the grammar ambiguity, after some internal discussion.

aturon added a commit to aturon/rust that referenced this pull request Dec 20, 2014

Stabilize cmp
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.

@aturon aturon referenced this pull request Dec 20, 2014

Merged

Stabilize cmp #20065

aturon added a commit to aturon/rust that referenced this pull request Dec 30, 2014

Stabilize cmp
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.

aturon added a commit to aturon/rust that referenced this pull request Dec 30, 2014

Stabilize cmp
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.

aturon added a commit to aturon/rust that referenced this pull request Dec 30, 2014

Stabilize cmp
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]

alexcrichton added a commit to alexcrichton/rust that referenced this pull request Dec 31, 2014

rollup merge of rust-lang#20065: aturon/stab-2-cmp
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

bors added a commit to rust-lang/rust that referenced this pull request Dec 31, 2014

auto merge of #20065 : aturon/rust/stab-2-cmp, r=alexcrichton
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 #20063.
However, there is no problem stabilizing the less general impls, since
generalizing later is not a breaking change.

r? @alexcrichton
@arthurprs

This comment has been minimized.

Copy link

arthurprs commented Mar 5, 2015

I'm trying to implement Ord to compare a struct Pair(K, V) against K

The RFC clearly states it's possible

but the docs says otherwise

This is what we have

trait Eq: PartialEq<Self>
trait Ord: Eq + PartialOrd<Self>

but I (and the RFC) expected this

trait Eq<Rhs: ?Sized = Self>: PartialEq<Rhs>
trait Ord<Rhs: ?Sized = Self>: Eq<Rhs> + PartialOrd<Rhs>

Is it a bug or oversight? What's the motivation?

I originally posted this at reddit

@eddyb suggested we made these traits unsafe.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented Mar 5, 2015

To expand on that: I believe implementations of Eq and Ord where the two sides aren't the same type are more prone to incorrectness.

Meanwhile, we can't depend on Eq or Ord guarantees for memory safety in optimizations or algorithms (e.g. sorting) because an incorrect implementation can be written without unsafe.
Making those two traits unsafe to implement has been thrown around for some time before we got unsafe trait which feels like the perfect solution.

#[deriving(Eq, Ord)] would only be allowed to impl both the partial traits and the total ones, at the same time, making them correct by default (it might be possible to not even emit unsafe impl from deriving, but I'm not familiar with OIBIT to say for sure).

cc @nikomatsakis @flaper87

@glaebhoerl

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Mar 5, 2015

@eddyb @arthurprs There is discussion of the unsafe trait approach in #926.

cuviper pushed a commit to cuviper/rayon that referenced this pull request Mar 28, 2017

Stabilize cmp
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]

@Centril Centril added the A-operator label Nov 23, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.