What is the reason for not having overloaded versions of fn?

Could you please explain to me why it was decided not to have overloaded versions. Instead I have to name function silly, like:

fn new()->Self
fn new_with_name()->Self
fn new_with_name_and_something_else()->Self
1 Like

See also: Is it possible to specialize HashMap Index for Copy types - #5 by withoutboats

But the main reason is that for a feature to be added to Rust you need to create an RFC. The RFC has to provide strong justification for adding the feature.

So the question is not "why not have this feature" but instead it's "why have this feature". Anyone wishing to add function overloading to the language needs to be able to give a detailed answer and explain how it interacts with other language features.


Your example doesn't really make much sense as an example for overloading, since all these signatures are the same type (?)

The main reason rust doesn't have overloading for regular functions is probably just simplicity, but also the fact that it doesn't go well with type inference.

For example if you have fn f(x: i32), and you call it in some other function like so: f(thing), then you can infer that thing is of type i32. But now imagine you add an overload fn f(x: f64). Now the "other function" from before maybe can't infer what is the type of thing and it can't even compile. So you broke some calling code just by adding functionality, not ideal.

That said rust is perfectly capable of doing the exact same thing as function overloading using the trait system. I'm linking an example of how you could do that. I didn't particularly wrote an explanation for it, but hopefully it's somewhat helpful :slight_smile: ...



Is there a simple way to overload functions? has some details, explanations and examples.


Not quite. At least not in all cases. Specifically, there isn't an equivalent to overloading a function with signatures with different arity. And actually, in that case the type inference point isn't as relevant either, since the compiler could use the arity to determine which types the function expects. You could maybe have a trait that is implemented for different types of tuples, and require the user to pass the arguments in as a tuple, but that would be kind of strange and awkward.

I think it would also be pretty difficult, to replace function overloads where multiple arguments are of different types across the different signatures. For example:

fn new(a: A, b: B)
fn new(c: C, d: D)

Then again, if you you have signatures like that, it might be a sign that maybe the functions aren't really doing the same thing and should have different names anyway.

This works just fine when you have the same trait impl'd for tuple types (A, B) and (C, D). Would be even better with specialization and/or variadic generics, probably.

Exactly – the feasibility of the above solution is the litmus test of whether this kind of "overloading" should be applied. This is the reason I regard overloading as an anti-pattern: if types and signatures are similar enough, then there's sufficient regularity that the corresponding requirements and guarantees can be pulled out in a trait, where it's more specific (less ad-hoc), more visible, more explicit, and as a result, more maintainable.

And if there's not enough similarity between the types so that this can be done, then they should not be treated identically.

I'll just add (to the excellent answers) that rust's namespacing of functions within a type really reduces the limitations of overloading in a way that maintains clarity. e.g.
Vec::with_capacity and HashMap::with_capacity or even f64::NAN. You have the same name modified for each type, but without the ugliness of manually prepending vec_ or similar (which can lead to inconsistent abbreviations). I really love being able to put functions and constants into a type's namespace like this, and feel like it accomplishes the same goal of being able to use the "right" name for a thing, while still being clear about what the thing is.


This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.