-
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
Limiting upstream crates may add new impl of trait in future versions
#2758
Comments
This restriction is really strict, sometimes backward compatibility is not possible, let alone forward compatibility. |
In unstable, one can circumvent this by telling the compiler that they won’t add new blanket impls for the type using So if |
I actually hardly understand this. If I want to build something that fits right away, why should I bother about something theoretically possible in the future? I'm fine with dealing the impl conflicts once they actually appear. |
You can work around this with macro ( But this is something which definitely should be fixed in language. I've seen it so many times already it's obvious that this was bad idea. BTW: my recent case was using |
I guess it's worth pointing to this tracking issue about negative impls: rust-lang/rust#68318 |
I'll leave here an example i've found if this "feature" causing problems pub trait Responseable {
fn into_stream (self) -> Box<dyn Stream<Item = u8>>;
}
impl<S: 'static + Stream<Item = u8>> Responseable for S {
#[inline(always)]
fn into_stream (self) -> Box<dyn Stream<Item = u8>> {
Box::new(self)
}
}
// conflicting implementations of trait `server::response::Responseable` for type `()`.
// upstream crates may add a new impl of trait `futures::Stream` for type `()` in future versions
impl Responseable for () {
#[inline(always)]
fn into_stream (self) -> Box<dyn Stream<Item = u8>> {
Box::new(futures::stream::empty())
}
} As you see, rust is basically saying me "well, maybe someone sometime tries to do the same as you, so you can't do it". |
^^ Exact same thing here, I try to implement a trait to use bytemuck::cast_slice for all Pod + Zeroable type. And the problem appear when I add for Vec |
This is bizarre, why is this still a thing? Literally anything can be changed and broken in a future version of a crate why pick this in particular??? |
I guess it's because new trait implementations are not commonly considered breaking changes (even though they can be). Suppose your crate It still feels unnecessarily strict to disallow all implementations that might conflict in the future, though. My use case is that I want my API to work with anything that implements IMO, a warning that an implementation might conflict in the future would be enough. The warning can be silenced with an annotation, and that annotation would immediately make clear what the problem is if a conflicting implementation is ever added. The warning could also remind you to use a stricter version range for the dependency. |
Adds `Lerp` implementations for Glam's math types (`Vec2` et al). Requires replacing the blanket primitive trait implementation for `Lerp` with a macro, thanks to some controversial Rust behavior: rust-lang/rfcs#2758 It's very silly, as types like `Vec2` are literally never going to implement Primitive traits, but there's no way to opt out. `num_traits` is still used for its convenient range-checking of integer conversions.
smh, guess I have to write a macro which calls a bunch of other macros, then. |
+1 here, would love for this to just be a warning. I'm having this issue warning me about stuff that as the OP said is stable: |
+1 this feels very arbitrary. As @SalsaGal said - there's basically an unlimited number of things a library author could do to break compatibility in consuming code, and explicitly preventing this isn't a stated goal of the language (nor should it be - at most maybe force a major version bump in the Cargo.toml?). Why is this thing in particular disallowed, but not any of the hundreds of other arbitrary ways someone could break their code for consumers. I ran into this trying to implement a trait defined in my code on various collection types - was all fine until I tried to add an impl on a <T: ExactSizeIterator> trait bound rather than a concrete type (because there's too many bespoke iterator impls out there for impl-ing on concrete types to be feasible). pub trait Foo {
fn foo(&self) -> &'static str;
}
impl<Item> Foo for Vec<Item> {
fn foo(&self) -> &'static str {
"I'm a Vec!"
}
}
impl<K, V> Foo for HashMap<K, V> {
fn foo(&self) -> &'static str {
"I'm a HashMap!"
}
}
impl<Item, T: ExactSizeIterator<Item = Item>> Foo for T {
fn foo(&self) -> &'static str {
"I don't compile :("
}
} It's valid code without the concrete impls above it, but fails with 'conflicting implementations of trait It sounds like the specialization feature might make this problem go away for this specific use case? Although currently enabling it doesn't change the error. |
I agree that this error make little sense in some cases (e.g. I'd prefer being able to specify the impls are Alternatively, there's |
Hello,
I've run into this one a few times now when working with generics, and I haven't really found a way to bypass it in most cases.
I completely get why this is here, "be careful, your behaviour may change if you update your crates, it may even stop compiling altogether" seems like a fair thing to warn against.
BUT: most of the time, when this error appears, it's for types that have been stabilised a while ago, and are way more likely never to add new implementations.
Wouldn't it be a good thing to be able to tell Rust "Yes, I know, this might conflict in the future, but with the current version, it's fine, so let me build until there ARE conflicts" ?
Rust's generics through traits and monomorphisation is one of my favourite features, but sometimes, in situations like this, Rust is TOO smart for its own good, and I think there should be ways to temper it.
This would also help with the problems that have been mentioned in the context of specialization and negative reasoning (maybe this could even enable negative reasoning which has the advantage of being more flexible and expressive than the currently selected "default" oriented specialisation), since breaking changes due to new implementations have always been limiting factors for them.
The text was updated successfully, but these errors were encountered: