LangDev

정적 타입 언어에서의 덕타이핑.

summerlight

안녕하십니까. 그간 눈팅으로 많은 것들을 배우다가 처음으로 글을 올려봅니다.

요즘 관심사 중 하나가 정적 타입 언어에서 효율적인 덕타이핑을 구현할 수 있는가입니다. 여기에서 효율적이라 함은 실행 시간에서 유한한 단계 내로, 즉 O(1)의 시간 복잡도로도 효율적으로 해당 함수를 호출할 수 있음을 의미하고, 정적 타입이라 함은 (유보되었지만) C++0x의 컨셉트와 비슷하게 타입 체킹까지 컴파일 시점에 완전하게 이루어짐을 의미합니다. 물론 모든 클래스-모든 함수 심볼에 대한 2차원 함수 포인터 배열을 만들면 무척 간단하게 구현이 가능합니다만 이건 제외하도록 합시다 OTL

이에 대해 관심을 가지는 이유로는 타입 안전성의 우월함 때문... 은 아니고 남들도 다 할 수 있는 주제는 별로 재미가 없어서 그렇습니다. (...) 그리고 정적 타입 언어의 지향점 중 하나가 요구 인터페이스와 구현 인터페이스의 우아한 분리인데, 덕 타이핑이 그 끝에 닿아있기 때문이죠.

일단 일반적인 OOP의 다형성 구현은 가상 함수 테이블을 이용하는데, 이 경우는 적용 가능한 모든 타입들에 대해 가상 함수들이 가지는 vtable상의 오프셋이 완전히 일치하기 때문에 1번의 간접 호출만으로 원하는 함수가 불려 나오는, 비교적 효율적인 구현이 가능합니다. 하지만 덕타이핑으로 넘어간다면 이렇게 간단한 해법이 나오질 않습니다.

이에 대해 C++0x의 컨셉트(이건 보류되었지만요.) 및 타 언어의 유사 기능들은 아예 각각의 타입들에 대해 똑같은 코드 판본을 찍어내는 방식으로 대응합니다. 하지만 이 경우는 코드 비대화가 발생하죠. 물론 수행 시간에 어휘 심볼들을 일일히 뒤지는 것보단야 효율적이겠지만.

Go 같은 경우도 덕타이핑을 구현했다고 해서 구경을 해봤는데, 어떻게 구현을 했는지는 잘 모르겠습니다. Haskell의 타입 클래스 역시 비슷한 느낌이지만 역시나 구현이 어떻게 되었는지는 잘 모르겠네요.

후배와 이야기하다가 랑데브 이야기가 나와서 오랜만에 랑데브를 들렀는데 첫 페이지에 아직도 이 글이 보이는군요. OTL 이건 중요한게 아니고...

글을 쓴 뒤 go에서 interface를 구현하는 방법에 대해 좀 찾아봤었는데, 의외로 간단하게 구현하고 있습니다. 컴파일 시점에는 타입 안전성의 검증과 더불어 클래스의 메타 데이터를 생성합니다. 그리고 런타임에는 메타 데이터를 기반으로 사용하려는 객체와 interface간의 디스패치 테이블을 만들어서 interface value에 포인터로 집어 넣고요. 이런 접근은 interface를 생성할 때를 제외하면 성능적인 측면에서 일반 vtable을 사용하는 것과 다를 바가 없다는 강점을 가집니다.

이는 프로세스가 가동된 뒤 인터페이스-클래스 조합이 처음으로 사용될 때 한 번씩 일어난다는군요. 물론 멀티쓰레딩 등의 이슈가 있기 때문에 실제로는 조금 더 복잡하겠습니다만. haskell 역시 비슷한 방식으로 구현한다고 합니다.

정적 타입 언어에서 보다 더 유연한 타입 시스템을 구현하시려는 분들은 참조하시기 바랍니다.

summerlight

Extensible record라는 것도 있습니다. 함수형 언어에 추가했을 때 타입 유추까지 가능합니다.

http://www.haskell.org/haskellwiki/Extensible_record

http://web.cecs.pdx.edu/~mpj/pubs/polyrec.html

http://www.mail-archive.com/haskell@haskell.org/msg20898.html

안기영