'not-equal' type bound, e.g. where T!=Y?

would there be any demand for a 'not-equal' constraint that can be added in where clauses,

the situation I ran into was: implementing generic conversions for a collection (a 'Vec3(T,T,T)' in my specific case but it could have been anything) , which in turn conflicted with the 'reflexive implementation of From' in 'core',e.g. T:From<T> conflicts with Vec3<A>:From<Vec3<B>> if B==A

I wondered if this demand would appear in any other situations, justifying a language feature.

here's the reddit thread,

I had a workable solution for my purposes, but it would have been nicer if this could be made to work; maybe there are other options aswell

maybe this could be fixed without a language feature with some convention around an 'IsNot' or something.. maybe there would be a way to disable the reflexive 'From' if it depended on something that you can disable ('negative trait bounds???') for your own types.

// original attempt pub struct Vec3 {pub x:T, pub y:T, pub z:T}
impl<A,B> From<Vec3<B>> for Vec3<A> where A:From<B> {
    fn from(b:Vec3<B>)->Self {
        Vec3::<A>{ x: b.x.into(), y: b.y.into(), z: b.z.into() }        
// error, conflicting impl in core..

I went through various experiments with a trait IsNot<B>{} , the best compromise for my use case was rolling that for types I care about and writing generic conversions to & from the 'f32' type.


I found this page while searching for a solution after trying to implement From<MyType<N>> for MyType<M>. Turns out this conflicts with the core crate:

   = note: conflicting implementation in crate `core`:
           - impl<T> From<T> for T;

The only ways I see around it are to either constrain M != N or to implement each conversion individually, which is going to be a lot of code considering M and N are numeric types.

1 Like

The "a lot of code" problem can mostly be solved with macros. Another way to solve this is specialization, as the impl<T> From<T> for T conversion would just be a special case of the N -> M conversion. Another option is const generics whereby you operationally convert one type into another by applying some sort of conversion formula. Then the fourth option, and IMO the least likely to ever happen, is a way to declare M != N.


The links in this issue explain why negative bounds are not allowed in general. In short, it would remove the ability for a new version of a library crate (including std) to add an impl to an existing type without breaking downstream crates.

Another option for converting from MyType<N> to MyType<M> is to create your own custom conversion trait or method, which you can implement generically. (One downside is that a custom trait is not quite as convenient or familiar as the standard From/Into traits.)


Yeah, this is an incredibly common desire. You'll notice that even std doesn't have that for things like Option, even though it would certainly like to.

Basically it'll need specialization, but the unstable implementation of that has been unsound for a long time. There's been some relatively recent work to try to create a stable min_specialization subset, though, that might be usable sooner than the full feature -- like how there's a subset of const generics that is planned to be stable soon.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.