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