Rust의 존재적 타입, 어떻게 다뤄야 할까?
Rust에서 `dyn Trait`와 `impl Trait`를 통해 존재적 타입을 표현하는 방법과 그 의미를 설명함
`∀` (For All)를 사용하여 존재적 타입을 다루는 'for-exists conversion' 기법을 소개하고, 트레이드오프(Trade-offs)를 분석함
연관 타입(Associated Types)과 `PhantomData`를 활용하여 존재적 타입을 '지우는(Erasing)' 시도를 보여줌
`Box`를 사용하여 존재적 타입을 묶는 과정에서 발생하는 문제점과 해결책을 제시하며, 수동적인 지우기(Manual Erasing)의 필요성을 강조함
존재적 타입(Existential Types)의 이해
본문은 Rust에서 `dyn Trait`와 `impl Trait`를 통해 존재적 타입을 표현하는 방법을 설명한다. `dyn Trait`는 특정 타입이 아닌, 트레이트(Trait)를 구현하는 모든 타입을 의미하며, `impl Trait`는 컴파일 타임에 결정되는 존재적 타입을 나타낸다. 이러한 개념은 타입 이론(Type Theory)의 존재량 한정자(Existential Quantifier)와 밀접하게 연관되어 있으며, Rust의 타입 시스템을 이해하는 데 중요한 기반이 된다.
For-Exists 변환(For-Exists Conversion)과 트레이드오프(Trade-offs)
저자는 존재적 타입을 다루는 한 가지 방법으로 'for-exists conversion'을 제시한다. 이는 `∃x.P(x) → Q ⟺ ∀x.(P(x) → Q)`의 원리를 활용하여, 존재적 타입을 전칭 한정자(Universal Quantifier)로 변환하는 방식이다. 이 방법은 간단하지만, `Box`와 함께 사용할 경우, 모든 사용 지점에서 전칭 한정자를 유지해야 하는 제약이 발생한다. 이는 코드 복잡도(Code Complexity)를 증가시키는 트레이드오프(Trade-offs)로 이어진다.
연관 타입(Associated Types)과 `PhantomData`를 이용한 지우기(Erasing)
저자는 연관 타입(Associated Types)과 `PhantomData`를 사용하여 존재적 타입을 '지우는(Erasing)' 시도를 보여준다. `PhantomData`를 통해 런타임에 영향을 주지 않으면서 타입 정보를 추가할 수 있다. 하지만, `Box`에 넣는 과정에서 연관 타입의 구체적인 타입을 지정해야 하는 문제가 발생한다. 이는 Rust의 타입 시스템이 단일 존재적 바운드(Single Existential Bound)만 지원하기 때문이다.
수동적인 지우기(Manual Erasing)의 필요성
Rust의 제약으로 인해, 저자는 여러 존재적 바운드를 완전히 자동적으로 지우는 것이 불가능하다고 결론 내린다. 대신, `Erased` 트레이트를 정의하여 각 함수 시그니처를 수동으로 수정하는 '수동적인 지우기(Manual Erasing)' 방법을 제시한다. 이 방법은 `dyn` 호환성(dyn-compatibility)을 확보하지만, 각 함수를 일일이 수정해야 하는 번거로움이 있다. 또한, `std::any::Any`를 사용하여 런타임에 타입을 처리해야 하는 단점이 존재한다.