That's a good question. A couple of things:
- Making every function generic that way is bad for compile times. That's because instead of compiling them once in the library, they have to be monomorphized on use in the application. You can refactor everything to be outlined to limit that, but it's questionable whether that's worth the effort.
- Making everything generic means that you can't use anything dependent on inference context when calling it. For example,
foo(Default::default())
or foo(s.parse())
won't work with the impl
trick (those two specific examples might not make sense for your case, but they're the easiest ones to explain).
- Making the
str
->String
allocation invisible tends to lead to "pervasive pessimization": something that's not really bad, but you lose the opportunity for the weak push to "did you maybe want a variable to not do that repeatedly?"
I agree. So what I would say is that the From
impls are still good (as well another for From<String>
probably), it's just the invisible calling of them that I suggest avoiding.
That means that you can always just do operate_on("hello".into())
, which is fairly minor overhead. And if you're going to call multiple things with the same id, it encourages let id = "hello".into(); foo(&id); bar(&id);
.
Oh, that's another good point: most of these should probably be taking &Identifier
, since you don't need to consume the String
every time. And operate_on(&"hello".into());
will work, but impl Into<&Identifier>
isn't going to because there's nowhere to borrow it from.
TL/DR: Keep the From
s, just have the caller do the .into()
instead of impl Into<_>
ing everything.