제거됨: 자동 적용

제거됨: 자동 적용 (Dropped: Auto-Application)

Scala 2에서는 인자 없는(nullary) 메서드를 인자 없이 호출할 때 빈 인자 목록 ()이 자동으로 채워졌어요. 이 자동 적용(auto-application)은 Scala 3에서 에러가 돼요. 이 변화와 그 이유, 그리고 예외가 적용되는 경우를 살펴볼게요.

출처: Scala 3 Reference

본문

이전에는 인자 없는(nullary) 메서드를 인자 없이 호출할 때 빈 인자 목록 ()이 암시적으로 삽입됐어요. 예를 들어 볼게요.

def next(): T = ...
next     // is expanded to next()

Scala 3에서 이 관용구(idiom)는 에러예요.

next
^
missing arguments for method next

Scala 3에서 적용(application) 문법은 파라미터 문법과 정확히 일치해야 해요. 이 규칙에서 제외되는 것은 Java에서 정의됐거나 Java에서 정의된 메서드를 오버라이드하는 메서드예요. 그런 메서드에 더 관대한 이유는, 그렇지 않으면 모든 사람이

xs.toString().length()

대신에

xs.toString.length

라고 써야 하기 때문이에요. 후자는 균일 접근 원칙(uniform access principle)에 부합하는 관용적인 Scala예요. 이 원칙은 객체 멤버를 필드에서 부수 효과가 없는 메서드로, 그 반대로도, 그 멤버에 접근하는 클라이언트에 영향을 주지 않고 바꿀 수 있어야 한다고 말해요. 결과적으로 Scala는 그런 "프로퍼티" 메서드를 () 파라미터 목록 없이 정의하도록 권장하고, 부수 효과가 있는 메서드는 그와 함께 정의하도록 권장해요. Java에서 정의된 메서드는 이런 구분을 할 수 없어요. Java에서는 ()가 항상 필수니까요. 그래서 Scala는 클라이언트 측에서 그 자유를 허용함으로써 문제를 고쳐요. 하지만 Scala가 모든 메서드 참조에 대해 그 자유를 허용하던 곳에서, Scala 3는 그것을 Scala 3 자신에서 정의되지 않은 외부 메서드의 참조로 제한해요.

하위 호환성을 위해, Scala 3는 당분간 Scala 2에서 정의됐거나 Scala 2에서 정의된 메서드를 오버라이드하는 인자 없는 메서드에 대해서도 ()를 자동 삽입해요. 지금까지 정의와 호출 사이의 대응이 Scala에서 강제되지 않았기 때문에, Scala 2 라이브러리에는 ()를 일관되지 않게 쓰는 메서드 정의가 꽤 많다는 게 밝혀졌거든요. 예를 들어 scala.math.Numeric에서

def toInt(): Int

인데, 다른 곳에서는 toInt를 파라미터 없이 써요. 그런 메서드 참조에 대해 엄격한 파라미터 대응을 강제하면 그 불일치가 클라이언트 코드에 전이돼서 바람직하지 않아요. 그래서 Scala 3은 Scala 2의 핵심 라이브러리가 정리될 때까지 그런 메서드 참조를 타입 검사할 때 더 관대한 선택을 해요.

인자 없는 메서드의 오버라이딩에도 더 엄격한 적합(conformance) 규칙이 적용돼요. 파라미터 없는(parameterless) 메서드를 인자 없는(nullary) 메서드로 오버라이드하거나 그 반대로 하는 것은 더 이상 허용되지 않아요. 대신 두 메서드는 파라미터 목록이 정확히 일치해야 해요.

class A:
  def next(): Int

class B extends A:
  def next: Int // overriding error: incompatible type

Java나 Scala 2 메서드를 오버라이드하는 메서드는 이 요구 사항에서 다시 제외돼요.

코드 마이그레이션 (Migrating code)

파라미터가 일관되지 않은 기존 Scala 코드는 -source 3.0-migration 아래에서 여전히 Scala 3로 컴파일할 수 있어요. -rewrite 옵션과 함께 쓰면 그 코드는 Scala 3의 더 엄격한 검사에 맞게 자동으로 다시 쓰여져요.

참고자료 (Reference)

더 자세한 내용은 Issue #2570과 PR #2716에서 볼 수 있어요.