Why does Jorge Ortiz advise to avoid method overloading?
Overloading is a powerful feature, but you should use it only as needed. Use it when you actually do need multiple methods with different parameters, but the methods do the same thing. That is, don't use overloading if the multiple methods perform different tasks.
The main disadvantage is that it requires the compiler to perform name mangling on the function name to include information about the argument types.
Overloaded methods must use different numbers or types of arguments to avoid ambiguity. If you create two methods in the same class that have the same name and accept two integers as arguments, the Java compiler will be unable to distinguish between the two, even if the input variables have different names.
Java doesn't supports operator overloading because it's just a choice made by its creators who wanted to keep the language more simple. Every operator has a good meaning with its arithmetic operation it performs. Operator overloading allows you to do something extra than what for it is expected for.
Overloading makes it a little harder to lift a method to a function:
object A { def foo(a: Int) = 0 def foo(b: Boolean) = 0 def foo(a: Int, b: Int) = 0 val function = foo _ // fails, must use = foo(_, _) or (a: Int) => foo(a) }
You cannot selectively import one of a set of overloaded methods.
There is a greater chance that ambiguity will arise when trying to apply implicit views to adapt the arguments to the parameter types:
scala> implicit def S2B(s: String) = !s.isEmpty S2B: (s: String)Boolean scala> implicit def S2I(s: String) = s.length S2I: (s: String)Int scala> object test { def foo(a: Int) = 0; def foo(b: Boolean) = 1; foo("") } <console>:15: error: ambiguous reference to overloaded definition, both method foo in object test of type (b: Boolean)Int and method foo in object test of type (a: Int)Int match argument types (java.lang.String) object test { def foo(a: Int) = 0; def foo(b: Boolean) = 1; foo("") }
It can quietly render default parameters unusable:
object test { def foo(a: Int) = 0; def foo(a: Int, b: Int = 0) = 1 }
Individually, these reasons don't compel you to completely shun overloading. I feel like I'm missing some bigger problems.
UPDATE
The evidence is stacking up.
UPDATE 2
UPDATE 3
scala> object O { def apply[T](ts: T*) = (); def apply(f: (String => Int)) = () } defined object O scala> O((i: String) => f(i)) // oops, I meant to call the second overload but someone changed the return type of `f` when I wasn't looking...
The reasons that Gilad and Jason (retronym) give are all very good reasons to avoid overloading if possible. Gilad's reasons focus on why overloading is problematic in general, whereas Jason's reasons focus on why it's problematic in the context of other Scala features.
To Jason's list, I would add that overloading interacts poorly with type inference. Consider:
val x = ... foo(x)
A change in the inferred type of x
could alter which foo
method gets called. The value of x
need not change, just the inferred type of x
, which could happen for all sorts of reasons.
For all of the reasons given (and a few more I'm sure I'm forgetting), I think method overloading should be used as sparingly as possible.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With