There probably isn’t much about it explicitly, because it’s a direct consequence of a different design choice: the desire to not have monomorphization-time errors in generics.
Take a function like this:
fn foo<T>(x: T) { bar(x) }
Today, that’s easy:
- the call to
bar
is to thebar
that’s in-scope at the definition offoo
-
bar
must be a function that accepts anything, sinceT
is unbounded
Imagine overloading existed. Both would be way harder:
- Which
bar
are we calling? Is it thebar
in-scope right now? If there are two in-scope right now, which of them? An overload ofbar
that doesn’t exist yet? Abar
in the same module where the concrete generic argument is defined? - When is
foo
even valid? Is it “whenever there’s abar
somewhere that happens to match what we need”? Do we need to like all the types for whichbar
exists in the bound somewhere?
Explicitly indirecting through the trait, rather than having everything be a potential indirection point, makes everything was easier, both to understand what’s happening and to implement.