최상위 정의
최상위 정의 (Top-level Definitions)
Scala 3부터는 소스 파일의 최상위 수준, 즉 패키지 아래에 바로 여러 종류의 정의를 쓸 수 있어요. Scala 2에서 하던 것보다 더 담백하게 코드를 시작할 수 있죠.
본문
이제 모든 종류의 정의를 최상위에서 작성할 수 있어요. 예시를 볼게요.
package p
type Labelled[T] = (String, T)
val a: Labelled[Int] = ("count", 1)
def b = a._2
case class C()
extension (x: C) def pair(y: C) = (x, y)
예전에는 type, val, def 정의를 꼭 패키지 오브젝트(package object)로 감싸야 했어요. 이제는 패키지 안에 그런 최상위 정의를 담은 소스 파일이 여러 개 있어도 되고, 한 소스 파일 안에서 최상위 값·메서드·타입 정의와 클래스, 오브젝트를 자유롭게 섞어 쓸 수 있어요.
컴파일러는 다음 범주에 해당하는 최상위 정의를 감싸는 합성 오브젝트(synthetic object)를 생성해요.
- 모든 패턴, 값, 메서드, 타입 정의
- 암시적(implicit) 클래스와 오브젝트
- 불투명 타입 별칭(opaque type alias)의 컴패니언 오브젝트
소스 파일
src.scala에 그런 최상위 정의가 있으면, 그것들은src$package라는 합성 오브젝트 안에 들어가요. 하지만 이 감싸기는 투명(transparent)해요.src안의 정의는 여전히 감싸고 있는 패키지의 멤버로 접근할 수 있거든요. 합성 오브젝트는 파일 끝, 다른 패키지 절·import·오브젝트/클래스 정의 뒤에 배치돼요. 참고로, 이렇게 감싸인 최상위 정의가 담긴 소스 파일의 이름은 바이너리 호환성과 관련이 있어요. 이름이 바뀌면 생성되는 오브젝트와 그 클래스의 이름도 바뀌거든요. 최상위main메서드def main(args: Array[String]): Unit = ...도 다른 메서드처럼 감싸져요. 이 메서드가src.scala에 있다면scala src$package같은 명령으로 커맨드 라인에서 실행할 수 있어요. 그런데 "프로그램 이름"이 맹글링(mangled)되므로,main메서드는 되도록 이름이 명시된 오브젝트 안에 두는 걸 권장해요.private의 개념은 정의가 감싸졌는지와는 무관해요. 최상위 정의에 붙은private는 항상 감싸고 있는 패키지 안 어디에서나 보여요. 이름이 같은 여러 최상위 정의가 오버로드된 변형(overloaded variant)이라면, 반드시 같은 소스 파일에 있어야 해요.