Jorge Ortiz 가 메서드 오버로딩을 피하라고 조언하는 이유는 무엇 입니까?
Jorge Ortiz 가 메서드 오버로딩을 피하라고 조언하는 이유는 무엇 입니까?
답변:
오버로딩은 메서드를 함수로 들어 올리는 것을 조금 더 어렵게 만듭니다.
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는 아마도 우리가 인식하는 것보다 더 많은 것을 정확하게 얻었습니다 .
Gilad와 Jason (retronym)이 제공하는 이유는 모두 가능하면 과부하를 피하는 매우 좋은 이유입니다. Gilad의 이유는 일반적으로 오버로딩이 문제가되는 이유에 초점을 맞추고, Jason의 이유는 다른 Scala 기능의 맥락에서 문제가되는 이유에 초점을 맞 춥니 다.
Jason의 목록에 오버로딩이 유형 추론과 제대로 상호 작용하지 않는다고 추가합니다. 중히 여기다:
val x = ...
foo(x)
추론 된 유형 x
이 변경 foo
되면 호출 되는 메소드가 변경 될 수 있습니다 . 의 값 은 x
변경 될 필요가 없습니다 x
. 모든 종류의 이유로 발생할 수 있는 유추 된 유형의 .
주어진 모든 이유 (그리고 몇 가지 더 잊고 있다고 확신합니다) 때문에 메서드 오버로딩은 가능한 한 적게 사용해야한다고 생각합니다.
foo
동일한 수의 매개 변수를 가진 모든 오버로드에 대해 동일해야합니다. 그렇지 않으면 잘못 설계되었습니다. 추론 변경의 기괴한 계단식 범위를 제한하기 위해 공용 메서드는 항상 반환 형식을 선언해야합니다. 이것이 버전 간의 Scala 바이너리 호환성에 영향을 미치는 문제 중 하나라고 생각합니다.
나는 조언이 특히 스칼라를위한 것이 아니라 일반적으로 OO를위한 것이라고 생각합니다.
재정의 는 괜찮고 다형성의 핵심이며 OO 디자인의 중심입니다.
반면에 과부하 는 더 문제가됩니다. 메서드 오버로딩을 사용하면 실제로 호출 될 메서드를 식별하기 어렵고 실제로 자주 혼동의 원인이됩니다. 과부하가 정말 필요한 이유도 거의 없습니다. 문제는 대부분의 경우 다른 방법으로 해결할 수 있으며 과부하가 냄새라는 데 동의합니다.
여기 에 기사가 있습니다 "오버로딩은 혼란의 원인"이 무엇을 의미하는지 잘 설명 가 있습니다. 이것이 낙담하는 주된 이유라고 생각합니다. 자바 용이지만 스칼라에도 적용된다고 생각합니다.