지연 given

지연 given (Deferred Givens)

스칼라 3.6은 트레이트 안에서 given 정의를 구현하는 새 방법을 도입했어요. 이렇게 써요.

given T = deferred

이런 given은 하위 클래스에서 자동으로 구현될 수 있어요. deferredscala.compiletime 패키지의 새로운 메서드로, 오직 트레이트에 정의된 given의 오른쪽 변으로만 나타날 수 있어요. 그 트레이트를 구현하는 어떤 클래스든 이 given의 구현을 제공해요. 정의가 명시적으로 제공되지 않으면, 상속하는 클래스의 스코프에서 타입 T의 given을 찾아 합성해요. 구체적으로 이 given을 찾는 스코프는 그 클래스의 환경(environment)에 파라미터를 더한 것이고 멤버는 포함하지 않아요. (멤버를 포함하면 재귀적 해석으로 이어질 수 있거든요.) 구현이 명시적으로 제공되면 그것은 구체 정의의 오버라이드로 간주하므로 override 수정자가 필요해요.

지연 given은 트레이트에서 컨텍스트 바운드를 깔끔하게 구현할 수 있게 해 줘요. 다음 예시를 볼게요.

trait Sorted:
  type Element : Ord

class SortedSet[A : Ord as ord] extends Sorted:
  type Element = A

컴파일러는 이걸 다음 구현으로 확장해요.

trait Sorted:
  type Element
  given Ord[Element] = compiletime.deferred

class SortedSet[A](using ord: Ord[A]) extends Sorted:
  type Element = A
  override given Ord[Element] = ord

클래스 SortedSetusing 절이 트레이트 Sorted의 지연 given에 구현을 제공해요.

지연 given의 명시적 구현을 제공할 수도 있어요. 다음 예시처럼요.

class SortedString[A] extends Sorted:
  type Element = String
  override given Ord[String] = ...

구현하는 given에는 override 수정자가 필요하다는 점에 주의하세요. 트레이트 Sorted의 지연 given이 구체(즉, 추상이 아닌) 정의로 간주되기 때문이에요. 어떤 의미에서 Sorted의 오른쪽 변에 있는 deferred는 (마법적이고 컴파일러가 지원하는) 매크로와 같아요. 다만 특이하게도 이 매크로의 구현이 하위 클래스에도 영향을 미치죠.

출처: Scala 3 Reference

본문

추상 given (Abstract Givens)

given은 추상 멤버일 수도 있는데, 제약이 하나 있어요. 반드시 명시적 이름을 가져야 한다는 거예요. 예시를 볼게요.

trait HasOrd[T]:
  given ord: Ord[T]

추상 given은 오른쪽 변이나 타입에 대한 인자 없는 given name: Type의 형태예요.

스칼라 3.6부터 추상 given은 지연 given으로 대체되면서 중복이 됐어요. 지연 given은 상속하는 클래스에서 자연스럽게 구현되기 때문에 인체공학적(ergonomics)이 더 좋아요. 그래서 추상 given의 정의를 채우는 보일러플레이트가 더 이상 필요 없어요.

따라서 추상 given에 의존하는 소프트웨어 아키텍처는 지연 given을 쓰도록 마이그레이션하는 것이 권장돼요. 추상 given은 스칼라 3.6에서 여전히 지원되지만, 시간이 지나 deprecated되고 단계적으로 없어질 가능성이 높아요.