Почему "избегать перегрузки метода"?

Почему Хорхе Ортис советует избегать перегрузки методов?

Ответы

Ответ 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

Доказательство складывается.

ОБНОВЛЕНИЕ 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.