Okay, so I've created a trait called Between and I've also created a generic implementation for it for every type that implements PartialOrd. I've also created an implementation of Between for the glam library's Vec2 struct. Vec2 does NOT implement PartialOrd, and yet I get this error:
error[E0119]: conflicting implementations of trait `Between` for type `Vec2`
--> src\util.rs:58:1
|
44 | impl<T> Between for T where T: PartialOrd {
| ----------------------------------------- first implementation here
...
58 | impl Between for Vec2 {
| ^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Vec2`
|
= note: upstream crates may add a new impl of trait `std::cmp::PartialOrd` for type `glam::Vec2` in future versions
Deleting Vec2's implementation results in the following error:
error[E0599]: can't compare `Vec2` with `Vec2`
--> src\ui\text_field.rs:76:27
|
76 | if !mouse_pos.between(&self.pos, &(self.pos + self.get_outer_size())) {
| ^^^^^^^ no implementation for `Vec2 < Vec2` and `Vec2 > Vec2`
Reading the first error you can see its rationale is that PartialOrd MAY be implemented in future versions despite not being implemented now. But so what??? Future versions may also remove some structs or traits or whatever that I'm using right now so if we extend that logic crates can't be used at all! I understand that if you HAVE to draw a line you might draw it there, but WHY draw a line at all?
Maybe I'm misunderstanding something. I hope I am. I hope there is an actual solution that allows for both the generic and Vec2 implementations to work, because as I'm seeing things right now it looks like the Rust compiler has decided to set an unreasonable and arbitrary limitation on what you are and aren't allowed to write.
That extended logic would indeed be awful. So there's a concept of semantic versioning, where some changes are considered breaking -- like removing some structs or traits -- and others are not considered breaking. The latter is required or else crates couldn't make any changes at all.
Any well-behaved crate obeys semantic versioning and doesn't delete structs and traits, breaking their downstream.
It's desired that it is not breaking to add new trait implementations to your own types, like Vec2 becoming PartialOrd. That's what the error is about: ensuring that glam can add the trait implementation without having to cut a new major version or break SemVer. If your implementation was allowed, they couldn't both be a well-behaved crate and add the implementation in the same major version, because adding the implementation would break your crate.
I understand what you're saying, but I think it's still odd for Rust to make such a restriction. There's no guarantee that updating a crate won't introduce breaking changes. Big crates do make breaking changes (for example winit removing WindowBuilder) and that's fine because the code breaks at compile time. If this issue were related to a breaking change happening at runtime then I'd understand why Rust would choose to not allow it, but this isn't the case here.
winit removed WindowBuilder when going from 0.29.15 to 0.30.0, which is allowed because that's a major semver bump.
No, that was fine because cargo won't implicitly select the updated but incompatible version, so the code won't break without you doing anything.
It would not be fine if winit did this change with version 0.29.16, because then a fresh compile of every project specifying winit = "0.29.15" would end up breaking because cargo would actually use the incompatible winit 0.29.16.
Wow. I had no idea. I still think that this restriction should at least have a way to disable it though, maybe as an unstable feature.
EDIT: negative_impls - The Rust Unstable Book Seems to be the closest thing to this, though you have to be the one defining the negative trait. For my specific situation I ended up creating a second trait that has the same functions as the first.