3 ответа:
перегрузка делает его немного сложнее поднять метод в функцию:
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 }
индивидуально, эти причины не заставляют вас полностью избегать перегрузка. Я чувствую, что упускаю некоторые большие проблемы.
обновление
доказательства накапливаются.
- это осложняет spec
- он может оказывать неявные преобразования непригодных для использования в целях шагами.
- это ограничивает вас, чтобы ввести значения по умолчанию для параметров только на одном из перегруженных альтернатив.
- потому что аргументы будут набраны без ожидаемый тип, вы не можете передать анонимные литералы функции, такие как '_.foo ' в качестве аргументов для перегруженных методов.
обновление 2
- вы не можете (в настоящее время) использовать перегруженные методы в объектах пакета.
- ошибки применимости труднее диагностировать для абонентов вашего API.
обновление 3
- статическое разрешение перегрузки может ограбить API всех типов безопасности:
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...
причины, которые Гилад и Джейсон (retronym) дают все очень веские причины, чтобы избежать перегрузки, если это возможно. Причины Гилада сосредоточены на том, почему перегрузка проблематична в целом, в то время как причины Джейсона сосредоточены на том, почему это проблематично в контексте других функций Scala.
к списку Джейсона я бы добавил, что перегрузка плохо взаимодействует с выводом типа. Рассмотрим:
val x = ... foo(x)
изменение в выводимом типе
x
может изменить чтоfoo
способ его вызывают. Элемент стоимостью наx
Не нужно менять, просто выведенный типx
, что может произойти по самым разным причинам.по всем приведенным причинам (и еще несколько я уверен, что забываю), я думаю, что перегрузка метода должна использоваться как можно реже.
Я думаю, что совет не предназначен для scala особенно, но для OO в целом (до сих пор я знаю, что scala должен быть лучшим из породы между OO и функциональным).
переопределение отлично, это сердце полиморфизма и занимает центральное место в дизайне OO.
перегрузка С другой стороны, это более проблематично. С перегрузкой метода трудно определить, какой метод будет действительно вызван, и это действительно часто источник путаница. Также редко можно найти оправдание тому, почему перегрузка действительно необходима. Проблема в большинстве случаев может быть решена другим способом, и я согласен, что перегрузка-это запах.
здесь статьи это хорошо объясняет, что я имею в виду с "перегрузка является источником путаницы", что, я думаю, является основной причиной, почему это обескураживает. Это для java, но я думаю, что это относится и к scala.