타입이 없이는 우아한 double dispatch는 불가능한 걸까요….
다음은 루비에서 정수와 새로 정의한 Roman 숫자간의 덧셈을 간략히 구현한 것입니다.
class Roman def initialize(val) @value = val end def coerce(other) if Integer === other [other, @value] else [Float(other), Float(@value)] end end end class IntSim def initialize(val) @value = val end def +(other) v1, v2 = other.coerce(@value) v1 + v2 end end int_3 = IntSim.new(3) vi = Roman.new(6) # Shows you how to compute 3 + vi. puts int_3 + vi
루비에서는 2개 숫자간의 덧셈시 int+int는 int, float+int는 float, float+float은 float같은 타입 conversion을 위해 coerce를 씁니다. 예를들어, 앞서의 예처럼 3+vi 를 호출하게 되면 3이 vi.coerce(3)을 호출합니다. 그러면 vi의 클래스인 Roman 쪽에서는 넘어온 3과 자기 자신의 타입을 바탕으로 하여 두개 숫자를 conversion합니다. 그러면 3의 operator+는 이 변환된 타입을 가지고 최종 결과를 계산합니다. (그래서 double dispatch라고 불립니다. 2번 호출하니까.)
문제는 이 예제를 본 Programming Ruby책이 잘못된 건지, 루비의 한계인건지 사실상 이와같은 double dispatch가 아무런 의미도 없다는 것입니다. double dispatch는 이러한 예와같이 두개의 hierarchy가 존재할 때, 양쪽 hierarchy에 따라서 적절히 메소드를 호출하기 위함입니다. 그리고 그 구현은 RTTI(i.e., reflection)과 if-else 사다리를 쓰는 방법, A의 a라는 메소드를 부르면 a는 B의 b를 부르는 방법이 있습니다. 물론 후자가 더 나은 방법이죠.
두번째 방법에서는, A의 a를 부르면, a라는 메소드에서는 자신의 type이 결정납니다. 따라서 B의 b를 부를때는 자신의 타입정보를 b에게 넘깁니다. b는 호출되자마자 B hierarhcy 측에서의 자신의 타입을 알게되면, 결국 모든 타입정보를 알게 된 셈이니까 양쪽의 타입에 근간한 dispatch가 가능한 것이죠.
하지만 앞서의 예에서는 IntSim에서 Roman 을 부르지만, Roman쪽에 “나는 int거든”이란 정보를 넘기지 않으니 다시 Roman에서는 if-else 사다리를 타고 있군요.. 이건 말이 안되는거 아닌지.
귀찮아서 대강 적절히 C++이라면 어떨까를 짜봤습니다.
class Roman { private: int val; public: Roman(int val):val(val) { } int operator+(const int &i) const { return val + i; } float operator+(const float &f) const { return val + f; } }; class Numeric { }; class IntSim: public Numeric { private: int val; public: IntSim(int val):val(val) { } int operator+(const Roman &o) const { return o.operator+(val); } }; class FloatSim: public Numeric { private: float val; public: FloatSim(float val):val(val) { } float operator+(const Roman &o) const { return o.operator+(val); } };
제가 생각할 땐 Programming Ruby 책이 잘못된 것 같군요.. 적어도 루비같은 duck typing언어에서는 아예 double dispatch를 포기하던가, 아니면 확실히 IntSim에서 Roman으로 갈때 Int측의 정보를 줄 수 있게 보조 장치를 만들어야 한다는 생각이 듭니다. 사실 Double Dispatch의 가장 좋은 솔루션은 Scott Myers 왈, “디자인을 새로해라” 잖아요.
Leave a Reply