You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
use std::convert::From;structSomeError;enumError<E>{One(SomeError),Two(E),}/// impl<E> From<SomeError> for Error<E> where E: !SomeError {impl<E>From<E>forError<E>{fnfrom(error:E) -> Self{Error::One(error)}}impl<E>From<SomeError>forError<E>{fnfrom(error:E) -> Self{Error::Two(error)}}
It's produces error:
rustc 1.18.0 (03fc9d622 2017-06-06)
error: main function not found
error[E0119]: conflicting implementations of trait `std::convert::From<SomeError>` for type `Error<SomeError>`:
--> <anon>:15:1
|
9 | / impl<E> From<E> for Error<E> {
10 | | fn from(error: E) -> Self {
11 | | Error::One(error)
12 | | }
13 | | }
| |_- first implementation hereadd
14 |
15 | / impl<E> From<SomeError> for Error<E> {
16 | | fn from(error: E) -> Self {
17 | | Error::Two(error)
18 | | }
19 | | }
| |_^ conflicting implementation for `Error<SomeError>`
error: aborting due to previous error
Reacted by Simon Sapin, Stepan Koltsov, Ximo Guanter, Avi Dessauer, Stepan Henek, Wojciech Daniło, Elichai Turkel, Ruben Anders, Li X.P., CJ and 88 more
Negative bounds have a lot of issues. Like the fact that implementing a trait becomes a breaking change. There's some related discussion in rust-lang/rfcs#1834 . There's probably more discussion in the internals forum.
Reacted by dimvoly, Cryotheum and Ricardo Fernández Serrata
Reacted by Michael Pfaff, Hezuikn, Ellie Pratt, MiguelX413, Gavrilikhin Daniil, Froloket64, kam821, Danilo Guanabara, Fernando Vega Catalán, Pierre Avital and 6 more
Oh and you might want to have a look at specialization. I think it allows your case without the Pandora's box of issues that negative trait bounds brings with it.
Reacted by est31, CJ, Felipe S. S. Schneider, Moja, Caleb Stanford, Matthieu JOLIMAITRE, Gor Madatyan, Froloket64, Max Kaplan, dimvoly and 3 more
AFAICT From's blanket implementation without use of the default keyword precludes specialization at the current time, unfortunately. An alternative formulation is the OIBIT trick for negative reasoning (someone mentioned this somewhere a while back; I don't remember who or where):
error[E0119]: conflicting implementations of trait `PrintAnything`:
--> src/main.rs:27:1
|
21 | impl<T: Integer> PrintAnything for T {
| ------------------------------------ first implementation here
...
27 | impl<T: Collection> PrintAnything for T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
error: aborting due to previous error
#68004 should probably be mentioned here. It's obviously not a complete negative bounds feature, and the motivation is largely unrelated, but it's a step in this direction.
error[E0119]: conflicting implementations of trait PrintAnything:
--> src/main.rs:27:1
|
21 | impl<T: Integer> PrintAnything for T {
| ------------------------------------ first implementation here
...
27 | impl<T: Collection> PrintAnything for T {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation
error: aborting due to previous error
I have run into pretty much the same situation.
"conflicting implementation" check should consider the type constraints!
Negative bounds have a lot of issues. Like the fact that implementing a trait becomes a breaking change. There's some related discussion in rust-lang/rfcs#1834 . There's probably more discussion in the internals forum.
This could be address by mandating complementary implementations. So if you want to write something like
impl<T: !Foo>BarforT{ \* ... *\ }
you'd be forced to implement
impl<T:Foo>BarforT{ \* ... *\ }
Therefore implementing Foo cannot break code because T has to implement Bar regardless of whether it implements T. I explained this more thoroughly here.
Reacted by Michael Pfaff, sodo, Eloff, Sebastian Urban, Cryptjar, jgarvin, Federico Stra, Moja, Vladas Zakrevskis, Antonio Yang and 57 more
I have a use-case where this would be really helpful:
I'm making some changes to trie-rs, a trie structure crate with two APIs: one that is map-like (Trie<Token, Value>) and another that is set-like (Trie<Token>).
The set trie is simply a newtype of the map trie (Trie<Token, ()>) that removes methods for accessing values (like HashSet is a newtype of HashMap in the standard library).
It would be nice to remove the newtype and simply make the set trie a type alias of the map trie by using negative bounds to disable methods for sets.
Auto traits for ZST and non-ZST types (i.e. where Value: NotZst)
Specialization with associated marker types (i.e. where Value: Size<Kind = NonZero> 😬)
Concrete negative bounds (IDK what it's called) (i.e. where Value != ())
But negative trait bounds was what first came naturally to me, plus the idea of a trait that is minimally implemented is aesthetically appealing to me (unlike auto traits which get implemented for everything).
Why should it be forbidden to call get_value ONLY if the if the value is ()?
There isn't a good reason for it.
Maybe you could make it a crate internal type or something, which you don't expose to public, so nobody would be able to create a Trie<Token, CrateInternalType> directly, and maybe you could ensure that no user would get a reference to such a type. This way you could just not call get_value for this type.
But not sure if something like this would work here.
@porky11 Yeah, it could use an internal type, but the point is that it would still need negative bounds or some alternative in order to merge the set and map variants.
Activity
oli-obk commentedon Jun 17, 2017
Negative bounds have a lot of issues. Like the fact that implementing a trait becomes a breaking change. There's some related discussion in rust-lang/rfcs#1834 . There's probably more discussion in the internals forum.
oli-obk commentedon Jun 17, 2017
Oh and you might want to have a look at specialization. I think it allows your case without the Pandora's box of issues that negative trait bounds brings with it.
soltanmm commentedon Aug 14, 2017
AFAICT
From's blanket implementation without use of thedefaultkeyword precludes specialization at the current time, unfortunately. An alternative formulation is the OIBIT trick for negative reasoning (someone mentioned this somewhere a while back; I don't remember who or where):kdy1 commentedon Nov 27, 2017
Does that works for a struct with (u8, u8)? Considering how oibit (Send/Sync) works, I don't think it would..
axos88 commentedon Jul 22, 2018
+1
I'm having trouble with implementing Debug for structs that have fields which are not Debug:
Another solution for my case would be if such a pattern could be implemented:
kennytm commentedon Jul 22, 2018
@axos88 This is already supported through specialization.
Convert points with components of one type to another
Convert points with components of one type to another
stepancheg commentedon Sep 14, 2019
@kennethbgoodin more complicated use cases are not possible with trait specialization.
For example:
kennytm commentedon Sep 14, 2019
It is possible if specialization is enhanced to recognize intersection (previously attempted in #49624) i.e.
(If you need to specialize to N traits like these you'll need 2N impls)
axos88 commentedon Sep 14, 2019
@kennytm That doesn't seem like a solution for anything with N >= 4...
quark-zju commentedon Apr 12, 2020
Would a subset of negative bounds be less problematic? For example,
!Sized? That alone might already solve some problems.Ixrec commentedon Apr 17, 2020
#68004 should probably be mentioned here. It's obviously not a complete negative bounds feature, and the motivation is largely unrelated, but it's a step in this direction.
tib888 commentedon May 9, 2020
I have run into pretty much the same situation.
"conflicting implementation" check should consider the type constraints!
newpavlov commentedon Jul 7, 2020
Another example which requires negative trait bounds:
I am not sure if specialization can help here.
tvallotton commentedon Jun 23, 2021
This could be address by mandating complementary implementations. So if you want to write something like
you'd be forced to implement
Therefore implementing
Foocannot break code becauseThas to implementBarregardless of whether it implementsT. I explained this more thoroughly here.JonahPlusPlus commentedon Mar 2, 2025
I have a use-case where this would be really helpful:
I'm making some changes to
trie-rs, a trie structure crate with two APIs: one that is map-like (Trie<Token, Value>) and another that is set-like (Trie<Token>).The set trie is simply a newtype of the map trie (
Trie<Token, ()>) that removes methods for accessing values (likeHashSetis a newtype ofHashMapin the standard library).It would be nice to remove the newtype and simply make the set trie a type alias of the map trie by using negative bounds to disable methods for sets.
e.g.
I also have
NodeRefandKeyReftypes that could be merged with the same pattern.Alternatives:
auto trait NotUnit {}andimpl !NotUnit for () {}sowhere Value: NotUnit)where Value: NotZst)where Value: Size<Kind = NonZero>😬)where Value != ())But negative trait bounds was what first came naturally to me, plus the idea of a trait that is minimally implemented is aesthetically appealing to me (unlike auto traits which get implemented for everything).
porky11 commentedon Mar 4, 2025
@JonahPlusPlus
This looks like bad design to me.
Why should it be forbidden to call
get_valueONLY if the if the value is()?There isn't a good reason for it.
Maybe you could make it a crate internal type or something, which you don't expose to public, so nobody would be able to create a
Trie<Token, CrateInternalType>directly, and maybe you could ensure that no user would get a reference to such a type. This way you could just not callget_valuefor this type.But not sure if something like this would work here.
JonahPlusPlus commentedon Mar 4, 2025
@porky11 Yeah, it could use an internal type, but the point is that it would still need negative bounds or some alternative in order to merge the set and map variants.