Justification for Rust not Supporting Function Overloading (directly)

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 the bar that’s in-scope at the definition of foo
  • bar must be a function that accepts anything, since T is unbounded

Imagine overloading existed. Both would be way harder:

  • Which bar are we calling? Is it the bar in-scope right now? If there are two in-scope right now, which of them? An overload of bar that doesn’t exist yet? A bar in the same module where the concrete generic argument is defined?
  • When is foo even valid? Is it “whenever there’s a bar somewhere that happens to match what we need”? Do we need to like all the types for which bar 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.

12 Likes