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


3 74

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 
}

индивидуально, эти причины не заставляют вас полностью избегать перегрузка. Я чувствую, что упускаю некоторые большие проблемы.

обновление

доказательства накапливаются.

обновление 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.