Відповіді:
Перевантаження набагато ускладнює підняття методу до функції:
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)
}
Ви не можете вибірково імпортувати один із набору перевантажених методів.
Існує більша ймовірність виникнення неоднозначності при спробі застосувати неявні погляди для адаптації аргументів до типів параметрів:
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("") }
Він може тихо зробити параметри за замовчуванням непридатними:
object test {
def foo(a: Int) = 0;
def foo(a: Int, b: Int = 0) = 1
}
В індивідуальному порядку ці причини не змушують вас повністю уникати перевантажень. Я відчуваю, що мені не вистачає деяких більших проблем.
ОНОВЛЕННЯ
Докази складаються.
ОНОВЛЕННЯ 2
ОНОВЛЕННЯ 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...
_.foo
проблеми полягає у обмеженому висновку Scala, а не в перевантаженні. Ви відповідаєте на запитання, але деякі причини пов’язані з іншими слабкими місцями Scala, які можна було б покращити. Перевантаження є ефективнішим, ніж виконання, що знижує диз’юнкцію, або декартовий твір імен викликає шум і відключає загальну семантику.
addIntToDouble
, addDoubleToInt
тобто декартовий продукт імен замість статичного введення для кожної загальної семантики. Заміна набору тексту іменуванням видається регресивною. Java отримала більше речей, ніж ми можемо визнати.
Причини, які наводять Гілад та Джейсон (ретронім), є дуже вагомими причинами, щоб уникнути перевантажень, якщо це можливо. Причини Гілада зосереджені на тому, чому перевантаження загалом проблематично, тоді як причини Джейсона зосереджені на тому, чому це проблематично в контексті інших особливостей Scala.
До списку Джейсона я б додав, що перевантаження погано взаємодіє з висновками типу. Розглянемо:
val x = ...
foo(x)
Зміна виведеного типу x
може змінити foo
метод, який викликається. Значення з x
необхідності не зміниться, тільки виведений типу x
, який може статися з різних причин.
З усіх наведених причин (і ще кількох, я впевнений, що забуваю), я думаю, що перевантаження методів слід застосовувати якомога економніше.
foo
має бути однаковою для кожного перевантаження з однаковою кількістю параметрів, інакше вона була розроблена неправильно. Що стосується обмеження сфери химерного каскаду змін висновків, то загальнодоступні методи завжди повинні оголошувати їх типи повернення. Я думаю, це була одна з проблем, що впливають на бінарну сумісність Scala між версіями.
Я думаю, що поради призначені не для Scala, а для ОО взагалі (поки що я знаю, що Scala повинна бути найкращою у своїй породі між OO та функціоналом).
Перевизначення - це нормально, це серце поліморфізму і є головним у дизайні ОО.
З іншого боку, перевантаження є більш проблематичним. З перевантаженням методів важко зрозуміти, який метод буде справді викликаний, і це справді часто викликає плутанину. Також рідко можна виправдати, чому перевантаження дійсно необхідні. Здебільшого проблему можна вирішити іншим способом, і я згоден, що перевантаження - це запах.
Ось стаття, яка чудово пояснює, що я маю на увазі під назвою "перевантаження - це джерело плутанини", що, на мою думку, є основною причиною, чому це не рекомендується. Це для Java, але я думаю, що це стосується і Scala.