컨텍스트 추상화
컨텍스트 추상화
Scala 3에서 컨텍스트 추상화가 어떻게 다시 설계됐는지, 그리고 그 덕분에 실제 코드가 어떻게 달라지는지 함께 살펴볼게요. 이번 장은 컨텍스트 추상화라는 큰 주제의 입구라서, 개념이 왜 생겼는지부터 잡고 가면 뒤의 장들이 훨씬 수월해져요.
출처: Scala 3 Book
본문
배경 (Background)
컨텍스트 추상화(contextual abstractions)는 쉽게 말해 컨텍스트(맥락)를 추상화하는 방법이에요. 이 하나의 패러다임이 실제로는 굉장히 다양한 용도로 쓰여요. 대표적인 예를 들어볼게요.
- 타입 클래스(type class) 구현하기
- 컨텍스트 확립하기
- 의존성 주입(dependency injection) 하기
- 능력(capability) 표현하기
- 새로운 타입 계산하기, 그리고 타입들 사이의 관계 증명하기
사실 이런 흐름은 다른 언어들에도 영향을 줬어요. Rust의 트레이트(trait)나 Swift의 프로토콜 확장(protocol extension)이 그 예고요. Kotlin에서는 컴파일 타임 의존성 해석으로, C#에서는 Shapes와 Extensions로, F#에서는 Traits로 각각 설계 제안이 올라와 있기도 해요. 컨텍스트 추상화는 Coq이나 Agda 같은 정리 증명기(theorem prover)에서도 흔히 볼 수 있는 기능이에요.
이 설계들은 용어는 제각각이지만, 모두 핵심 아이디어인 용어 추론(term inference) 의 변형이에요. 용어 추론이 뭐냐면, 타입이 주어지면 컴파일러가 그 타입을 갖는 "표준(canonical)" 용어를 스스로 합성해 내는 걸 말해요.
Scala 3의 재설계 (Scala 3 Redesign)
Scala 2에서는 정의(메서드와 값)나 매개변수를 implicit로 표시해서 컨텍스트 추상화를 지원했어요(컨텍스트 매개변수 참고).
Scala 3은 컨텍스트 추상화를 처음부터 재설계했어요. Scala 2에서 이 개념들이 조금씩 "발견"된 데다가, 이제는 잘 알려지고 이해된 상태라서 재설계가 그 지식을 충분히 활용할 수 있었죠.
Scala 3의 설계는 메커니즘(mechanism) 보다는 의도(intent) 에 초점을 맞춰요. 즉 하나의 강력한 implicit 기능을 제공하는 대신, 용도별로 여러 기능을 나눠서 제공해요.
- 클래스의 사후 확장 (Retroactively extending classes). Scala 2에서는 암시적 변환이나 암시적 클래스로 확장 메서드를 인코딩했어요. 반면 Scala 3에서는 확장 메서드가 언어 자체에 직접 내장되어, 더 나은 오류 메시지와 개선된 타입 추론을 얻을 수 있어요.
- 컨텍스트 정보 추상화 (Abstracting over contextual information). using 절을 쓰면 호출 컨텍스트에서 사용 가능한 정보를 추상화하고 암시적으로 전달할 수 있어요. Scala 2 implicit보다 개선된 점은, using 절을 타입으로 지정할 수 있다는 거예요. 그 덕분에 함수 시그니처에서 명시적으로 참조되지 않는 변수 이름을 생략할 수 있죠.
- 타입 클래스 인스턴스 제공 (Providing Type-class instances). given 인스턴스를 쓰면 특정 타입의 표준 값을 정의할 수 있어요. 이렇게 하면 구현 세부사항을 새지 않으면서 타입 클래스 프로그래밍이 훨씬 간결해져요.
- 한 타입을 다른 타입으로 보기 (Viewing one type as another). 암시적 변환은
Conversion이라는 타입 클래스의 인스턴스로 맨 바닥부터 재설계됐어요. - 고차 컨텍스트 추상화 (Higher-order contextual abstractions). 완전히 새로운 컨텍스트 함수 기능 덕분에 컨텍스트 추상화가 일급 시민(first-class citizen)이 됐어요. 라이브러리 작성자에게 중요한 도구이며, 간결한 도메인 특화 언어(DSL)를 표현할 때도 유용해요.
- 컴파일러의 실질적인 피드백 (Actionable feedback from the compiler). implicit 매개변수를 컴파일러가 해석하지 못하면, 문제를 고칠 수 있는 import 제안을 알려줘요.
장점 (Benefits)
이런 Scala 3의 변화는 용어 추론을 언어의 나머지 부분과 더 잘 분리해 줘요.
- given을 정의하는 방법이 하나뿐이에요
- implicit 매개변수와 인자를 도입하는 방법이 하나뿐이에요
- given을 import하는 방법이 별도로 있어서, 일반 import 속에 숨지 않아요
- 암시적 변환을 정의하는 방법이 하나뿐이고, 명확히 그렇게 표시되며 특별한 문법도 필요 없어요
이 변화들이 주는 이점은 이래요.
- 새 설계가 기능 간 상호작용을 피하고 언어를 더 일관되게 만들어요
- implicit을 배우기 쉽고, 남용하기 어렵게 해요
- implicit을 쓰는 Scala 프로그램의 95%에서 명확성을 크게 높여줘요
- 원칙적이면서도 접근 가능하고 친숙한 방식으로 용어 추론을 가능하게 할 잠재력이 있어요
이번 장은 이 새로운 기능들을 다음 절들에서 하나씩 소개할 거예요.