Making a data structure generic is causing much pain

I will play devil's advocate and support @H2CO3 's argument by showing how the type might not even be created. Suppose that some downstream code wants the ability to optionally construct an IRI:

use iri::Iri;

pub enum MyWrapper<X> {
    Iri(Iri<X>),
    SomethingElse(X),
}

Here, if Iri has a built-in requirement that A: Borrow<str>, then it prevents this downstream code author from using MyWrapper<&[u8]> even though MyWrapper::<&[u8]>::SomethingElse ought to be able to exist. To work around this, the downstream code author will need to redesign MyWrapper in terms of a trait (and possibly some dynamic dispatch).

In retrospect, due to the implications that these bounds have on downstream code, I think that after Implied Bounds is implemented, the general recommendation would likely still be to not use them unless necessary. (they are necessary for things like core::iter::Peekable and core::borrow::Cow which need to refer to associated types like Self::Item and Self::Owned)


(of course, there is also the more commonly brought up point that, in some alternate universe where e.g. HashMap had bounds on the struct, then HashMap::new would require Hash and Eq when they currently do not. I choose not to focus on this argument because I don't find it nearly as compelling; Putting the map into an Option should serve the vast majority of use cases, except maybe some niche cases that involve codegen or backwards compatibility with pub fields)

6 Likes