왜 "메서드 오버로딩을 피해야합니까?"


78

Scala가 Java의 유형 삭제를 상속한다는 사실과 관련이 있습니까?
Justin Niessner

1
@Justin : 유형 삭제가 이것과 무슨 관련이 있습니까?
missingfaktor 2010 년

6
Jorge Ortiz에게 왜 그가 메소드 오버로딩에 대해 조언하는지 물어 보지 않겠습니까?
John

Jorge의 원래 의도를 모르기 때문에 적용 가능한지 확실하지 않지만 : michid.wordpress.com/2008/02/08/…
Justin Niessner

12

답변:


109

오버로딩은 메서드를 함수로 들어 올리는 것을 조금 더 어렵게 만듭니다.

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...

2
현재 특정 경우에 과부하로 인해 트리거되는 scalac에도 버그가 있습니다. issues.scala-lang.org/browse/SI-7596 .
cvogt

2
처음 두 가지 문제는 모든 유효한 오버로딩 사용에 영향을주지 않습니다. 신청 버그 리포트 3 문제에 대한합니다. 기본값에 대한 제한은 선택 사항 이며 이론적으로 수정할 수 있습니다. _.foo문제의 결함은 오버로딩이 아닌 Scala의 제한된 유형 추론입니다. 당신은 질문에 대답하지만, 그 이유 중 일부는 개선 될 수있는 Scala의 다른 약점 때문입니다. 오버로딩은 분리를 런타임 다운 캐스트하는 것보다 더 효율적이거나 이름의 데카르트 곱이 시끄럽고 공유 의미 체계에서 연결이 끊어집니다.
Shelby Moore III

3
Typeclasses는 현재 일류 공용체 유형이 없기 때문에 일반적으로 사용할 수 없습니다 . 그래, 나는 Scala 커뮤니티에서 그 태도를 보았지만 대신 addIntToDoubleaddDoubleToInt, 즉 모든 공통 의미론에 대해 정적 타이핑 대신 이름의 데카르트 곱을 상상해 보라 . 타이핑을 네이밍으로 바꾸는 것은 회귀적인 것 같습니다. Java는 아마도 우리가 인식하는 것보다 더 많은 것을 정확하게 얻었습니다 .
Shelby Moore III

2
나는 토론 스레드 (이전 의견에서 언급 한 버그 보고서에 대해)에 "What is evil IMO는 오버로딩이 아닌 것으로 예상하거나 공통 의미에 대해 하나의 이름을 갖는 것의 중요성을 감소시키는 것" 이라고 썼습니다 .
Shelby Moore III

2
대답과 주석은 나에게 매우 순진 해 보이며 오버로딩을 사용하는 가장 중요한 이유는 언급하지 않습니다. 메서드가 실제로 전달되는 유형에 따라 매우 다른 내부 논리를 수행해야하는 경우입니다. "암시 적 사용"에 대한 대답은 즉시 실패합니다. 한 개체에서 특수 논리를 구현하는 다른 유형으로의 가능한 변환이 없을 수 있기 때문입니다.
ely

8

Gilad와 Jason (retronym)이 제공하는 이유는 모두 가능하면 과부하를 피하는 매우 좋은 이유입니다. Gilad의 이유는 일반적으로 오버로딩이 문제가되는 이유에 초점을 맞추고, Jason의 이유는 다른 Scala 기능의 맥락에서 문제가되는 이유에 초점을 맞 춥니 다.

Jason의 목록에 오버로딩이 유형 추론과 제대로 상호 작용하지 않는다고 추가합니다. 중히 여기다:

val x = ...
foo(x)

추론 된 유형 x이 변경 foo되면 호출 되는 메소드가 변경 될 수 있습니다 . 의 x변경 될 필요가 없습니다 x. 모든 종류의 이유로 발생할 수 있는 유추 된 유형의 .

주어진 모든 이유 (그리고 몇 가지 더 잊고 있다고 확신합니다) 때문에 메서드 오버로딩은 가능한 한 적게 사용해야한다고 생각합니다.


2
그렇게하지 않으려면 x에 대한 유형을 선언합니다. 당신이 그것을 선언하지 않는다면 당신은 그것이 변경되기를 바라는 것입니다. 의 의미는 foo동일한 수의 매개 변수를 가진 모든 오버로드에 대해 동일해야합니다. 그렇지 않으면 잘못 설계되었습니다. 추론 변경의 기괴한 계단식 범위를 제한하기 위해 공용 메서드는 항상 반환 형식을 선언해야합니다. 이것이 버전 간의 Scala 바이너리 호환성에 영향을 미치는 문제 중 하나라고 생각합니다.
Shelby Moore III

1

나는 조언이 특히 스칼라를위한 것이 아니라 일반적으로 OO를위한 것이라고 생각합니다.

재정의괜찮고 다형성의 핵심이며 OO 디자인의 중심입니다.

반면에 과부하 는 더 문제가됩니다. 메서드 오버로딩을 사용하면 실제로 호출 될 메서드를 식별하기 어렵고 실제로 자주 혼동의 원인이됩니다. 과부하가 정말 필요한 이유도 거의 없습니다. 문제는 대부분의 경우 다른 방법으로 해결할 수 있으며 과부하가 냄새라는 데 동의합니다.

여기 에 기사가 있습니다 "오버로딩은 혼란의 원인"이 무엇을 의미하는지 잘 설명 가 있습니다. 이것이 낙담하는 주된 이유라고 생각합니다. 자바 용이지만 스칼라에도 적용된다고 생각합니다.


2
그리고 Scala는 어쨌든 기본적으로 OO 언어가 아닙니다.
Daniel Earwicker

4
@ ewenli-Jorge는 스칼라 커뮤니티에서 잘 알려져 있으며 Rahul이 제공 한 링크는 Jorge의 스칼라 팁 중 하나 였지만 , 질문의 의도 인 scala대해 오버로딩이 특히 나쁜 이유에 대한 답변이 없습니다 . 또한 질문이 어떤 식 으로든 혼동되었다고 결정한 이유를 모르겠습니다. 완전히 정당하지 않기 때문에 답변에서 이것을 제거해야합니다. -1
oxbow_lakes

6
@Daniel Scala 주로 OO 언어입니다. 그렇게 생각하지 않는 이유는 무엇입니까?
Daniel C. Sobral

3
오, 경쟁 기능적 언어 의 제작자는 Scala가 충분히 기능적이라고 생각하지 않습니다! 큰 충격! :)
Daniel Earwicker

3
@Daniel Scala는 다중 패러다임 일 수 있지만 여전히 주로 객체 지향 언어입니다. Scala의 기능적 특성은 객체 지향 기능으로 구현 됩니다 . 가장 기능적인 Scala 프로그램조차도 객체와 각각의 클래스 및 특성으로 만 구성됩니다. 이제 Martin Odersky는 자신의 언어에 대해 원하는 것은 무엇이든 말할 수 있습니다 (결국 그의 언어입니다).하지만 엄격하게 기술적 인 평가에서 Scala는 주로 객체 지향적입니다. 여기서 "주로"는 다른 모든 것이이 특성을 기반으로한다는 것을 의미합니다. .
Daniel C. Sobral
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.