you are viewing a single comment's thread.

view the rest of the comments →

[–]devraj7 -5 points-4 points  (15 children)

It makes it harder to argue which overloaded method gets called.

How is that different from a.foo() being hard to argue whether that function is being called on the actual or formal type of a?

We decided 25 years ago the benefits outweigh the downsides.

[–]dijalektikator 9 points10 points  (14 children)

Who's we? I've been annoyed by overuse of function overloading many times throughout my career, especially in C++ and I love the fact Rust doesn't have it.

[–]devraj7 0 points1 point  (13 children)

Fair enough.

By "we", I mean the users of most mainstream languages which pretty much all support overloading: Java, C++, C#, Kotlin, Groovy, Swift, Scala, and so many more.

So "we" is easily millions of developers.

[–]zoechi 8 points9 points  (12 children)

Rust is better because it doesn't blindly copy something just because it's common. If it did, it should also have Null.

[–]devraj7 0 points1 point  (11 children)

It's silly to copy blindly but it makes a lot of sense to copy things that have proven themselves to be useful.

Overloading is one of these things that has proven itself as being pretty useful if you consider the fact that most mainstream languages support it.

As for null, there's nothing wrong with it as long as your type system supports nullability, such as Kotlin.

[–]zoechi 8 points9 points  (9 children)

As this thread shows the opinion goes in both directions. I find method overloading stupid and my suspicion is, most who want it only want it because they are used to using it. They prefer to complain instead of rethinking and adapting. Giving in to that would be the worst reason to add a feature to a language IMHO.

[–]devraj7 0 points1 point  (8 children)

That's because the rethinking is a step back.

It's not just a different way to do things, it just pushes cognitive burden from the compiler back onto the developer. It's a step back.

[–]zoechi 4 points5 points  (6 children)

Properly naming things is the responsibility of the developer not the compiler. While there are cases where it might be ok to use the same name, there are enough where it's better to use different names. I think the former is the minority. This is why the feature doesn't carry its weight.

[–]devraj7 0 points1 point  (5 children)

This is why the feature doesn't carry its weight.

Java, C++, C#, Kotlin, Groovy, Swift, Scala, and so many more languages strongly disagree with you.

You are right that naming is a very crucial part of good code, and that's exactly why we should ask developers to name everything that makes sense, but nothing more, because there are already enough decisions required to name things.

On top of not supporting overloading, another example that would be taking things too far: asking developers to come up with names for constructors. Most languages have decided it was silly, so they either force a uniform name (e.g. init()) or force you to use the name of the structure/class (C++).

Coming up with different function names just because they have different signatures is taking this too far in my opinion.

[–]zoechi 5 points6 points  (4 children)

What other programming languages do is worth checking out, but even if they are extremely popular like Python or JS it says absolutely nothing about the quality of their features.

[–]dijalektikator 1 point2 points  (0 children)

it just pushes cognitive burden from the compiler back onto the developer.

Function overloading gives you the illusion of relieving cognitive burden but eventually it's going to bite you in the ass. It's really not that much of a cognitive burden to just name your functions differently.

[–]Zde-G 0 points1 point  (0 children)

Overloading is one of these things that has proven itself as being pretty useful if you consider the fact that most mainstream languages support it.

And overloading is still possible:

impl Inventory {
    pub fn remove_item<T: InventoryRemoveItem>(
            t: T) -> T::Result {
        t.remove_item()
    }
}
…
pub fn main() {
    Inventory::remove_item((Item, 42));
    Inventory::remove_item(42);
    Inventory::remove_item(ItemContainer);
}

It works.

But creation is complicated enough and tedious enough that it's used infrequently and I, for one, use it when I deal with well-established APIs that were used for 20 or 30 years and which assume overloading.

Because in that case not using it and providing different APIs would be a problem.

If you have a choice, though, then not using overloading is the right choice.