Creating mutually exclusive generics, or Excluding specific types from a Generic Parameter

This touches on a lot of deep areas of bounds and coherence that are hard to summarize, so largely this will be a collection of links to pursue if you are interested. The TL;DR is -- that's been considered many times, and it is desired, but we're not there yet -- probably not close.

Re: negative_impls,

  • It's the leading edge for disjoint blanket implementations, but
  • Currently they are quite limited and do not influence coherence, however
  • There is an MCP and now an initiative to integrate them into coherence
    • Which you would need for your example
    • However-however, if things haven't changed since the MCP, even this doesn't allow !Trait in a where clause yet. So that is still quite a ways out.

A more general term for basing coherence on what isn't implemented is "negative reasoning". The Rust teams are usually careful about allowing this as it is quite brittle.

A main motivator for having negative trait bounds is mutually exclusive traits. It's been proposed before, and indeed, you can read about the roots of negative_impls in the discussions.

In some of these issues, the ability to say where T != U specifically has come up, to which Niko notes:

we haven't implemented support for equality bounds yet, and for good reasons, so I wouldn't want to officially support inequality bounds. They also have interactions with inference (which is currently driven by unification). (That said, just like region bounds, I suspect we could eventually support these as a kind of "after-the-fact" check, rather than having them inform inference in any way.)

But there is one place where equality bounds are supported today -- in associated type bounds.

fn f<I: Iterator<Item=i32>>(iter: I) { /* ... */ }

So how about incorporating some negative reasoning around those bounds? Two implementations bound on explicit, distinct associated types certainly can't overlap. That has been considered as well:

6 Likes