트레이트 파라미터

트레이트 파라미터 (Trait Parameters)

Scala 3부터는 트레이트도 클래스처럼 파라미터를 가질 수 있어요. 그래서 트레이트를 만들 때 필요한 값을 생성 시점에 바로 넘겨줄 수 있죠.

출처: Scala 3 Reference

본문

Scala 3는 클래스가 파라미터를 갖듯이, 트레이트도 파라미터를 가질 수 있게 해 줍니다.

trait Greeting(val name: String):
  def msg = s"How are you, $name"

class C extends Greeting("Bob"):
  println(msg)

트레이트에 전달되는 인자는 트레이트가 초기화되기 직전에 바로 평가돼요. 트레이트 파라미터에서 한 가지 신경 쓸 부분은 모호함(ambiguity)을 어떻게 막느냐예요. 예를 들어 Greeting을 다른 파라미터로 두 번 확장하려고 시도할 수 있겠죠.

class D extends C, Greeting("Bill") // error: parameter passed twice

그럼 "Bob"이 출력돼야 할까요, "Bill"이 출력돼야 할까요? 사실 이 프로그램은 불법이에요. 아래 트레이트 파라미터 규칙 중 두 번째 규칙을 어기기 때문이죠.

  • 클래스 C가 파라미터화된 트레이트 T를 확장하는데 그 슈퍼클래스는 그렇지 않다면, CT에 인자를 반드시 넘겨야 해요.
  • 클래스 C가 파라미터화된 트레이트 T를 확장하고 그 슈퍼클래스도 마찬가지라면, CT에 인자를 넘기면 안 돼요.
  • 트레이트는 부모 트레이트에 절대 인자를 넘기면 안 돼요. 파라미터화된 트레이트 Greeting을 확장한 트레이트를 볼게요.
trait FormalGreeting extends Greeting:
  override def msg = s"How do you do, $name"

규칙대로 Greeting에는 인자를 넘기지 않아요. 그런데 이렇게 하면 FormalGreeting을 확장하는 클래스를 정의할 때 문제가 생겨요.

class E extends FormalGreeting // error: missing arguments for `Greeting`.

E를 올바르게 쓰는 방법은 GreetingFormalGreeting 둘 다 확장하는 거예요(순서는 상관없어요).

class E extends Greeting("Bob"), FormalGreeting

컨텍스트 파라미터가 있는 트레이트 (Traits With Context Parameters)

이 "명시적 확장 필요" 규칙은, 빠져 있는 트레이트가 컨텍스트 파라미터만 가질 때는 완화돼요. 그런 경우 트레이트 참조가 추론된 인자와 함께 추가 부모로 암시적으로 삽입되거든요. 예를 들어 그리팅(greeting)에서 호칭(addressee)이 ImpliedName 타입의 컨텍스트 파라미터인 변형을 볼게요.

case class ImpliedName(name: String):
  override def toString = name

trait ImpliedGreeting(using val iname: ImpliedName):
  def msg = s"How are you, $iname"

trait ImpliedFormalGreeting extends ImpliedGreeting:
  override def msg = s"How do you do, $iname"

class F(using iname: ImpliedName) extends ImpliedFormalGreeting

마지막 줄의 F 정의는 암시적으로 이렇게 확장돼요.

class F(using iname: ImpliedName) extends
  Object,
  ImpliedGreeting(using iname),
  ImpliedFormalGreeting

명시적으로 언급하지 않았던 슈퍼 트레이트 ImpliedGreeting이 삽입된 걸 볼 수 있어요.

참고 자료 (Reference)

더 자세한 내용은 Scala SIP 25를 참고하세요.