You're running into something called Coherence. That is, the compiler needs a way to always determine whether a type implements a particular trait and if so, which impl block should it use.
As has already been mentioned, the problem with allowing both
Blarg impls is that if some type
Foo implements both
BlargB it's not possible to decide which impl to use for
<T as Blarg>::blarg().
Your proposition of just making it a compile error to implement
BlargB at the same time, while seemingly fine at first glance, has a couple problems... The most severe being that it moves the compilation error away from the code which is at fault (the overlapping
impl<T: BlargXXX> Blarg for T blocks) and over to where it is used.
This is how C++ templates work and leads to hard-to-debug compile errors and non-local reasoning.
Depending on your situation, you've got a variety of tools at your disposal.
- Specialisation - if the compiler can see that one implementation is strictly more specific than another, the decision is no longer ambiguous
- A newtype wrapper which implements
BlargA, and another wrapper which does the same for
- Use helper functions instead of a helper trait
- Add another layer of indirection (see things like the
Blarg (or the specialised
BlargB) so you don't get into this situation (probably not a helpful response, but worth mentioning anyway)