2009.08.27
開発

ダックタイピング

 Smalltalk、Ruby、Pythonのような動的型付けオブジェクト指向プログラミング言語の特徴にダックタイピング(Duck Typing)というものがあります。なんでこんな名前がついたのかというと、「家鴨(Duck)のように歩いて、鳴くのだから、これはきっと家鴨に違いない」という、台詞からきています。
 さて、C++のような静的型付けオブジェクト指向言語では、クラスの継承によって、オブジェクトが何であるかを認識します。例えば、非常に良く似たクラスAとBがあったとします。このとき、クラスAを引数として取る関数testを定義します。このとき、クラスBのオブジェクトを渡して、呼び出すことができません。

class   A {
    public:
    void      methodA(){
        printf( "methodA on A\n" );
    }
};
class   B {
    public:
    void      methodA(){
        printf( "methodA on B\n" );
    }
};

void        test(A *obj)
{
    obj->methodA();
}

//
    A	*a = new A;
    B	*b = new B;
    test( a );        // 正常
    test( b );        // エラー

 この場合、ベースになるクラスを作って継承することで、汎用化した関数を書くことができます。

class   Base {
    public:
    virtual void      methodA() = 0;
};
class   A : Base {
    public:
    void      methodA(){
        printf( "methodA on A\n" );
    }
};
class   B : Base{
    public:
    void      methodA(){
        printf( "methodA on B\n" );
    }
};
void        test(Base *obj)
{
    obj->methodA();
}
//
    A	*a = new A;
    B	*b = new B;
    test( a );        // 正常(AはBaseから継承されているから)
    test( b );        // 正常(BもBaseから継承されているから)

 PHPの場合は、動的型付けオブジェクト指向言語ですから、こんな面倒なことをする必要はありません。同じように呼出できるメソッドがあれば、同じクラスのように振舞います。

    class   A {
        function    methodA(){
            print "methodA on A\n";
        }
    }
    class   B {
        function    methodA(){
            print "methodA on B\n";
        }
    }
    function    test($obj)
    {
        $obj->methodA();
    }
    $a = new A;
    $b = new B;
    test($a);
    test($b);

 さてRubyではこのあたりの考え方をさらに一歩押し進めて、動的にクラスにメソッドを追加できるようになっています。以下は組み込みの文字列であるStringクラスにメソッドを追加した例です。

class   String
    def methodA()
        print "methodA on String"
    end
end

"string".methodA()      //  methodA on String

 ここまでくると気をつけないととんでもない拡張をしてしまって後でこまることになります。しかし、工夫次第では非常に面白いこともできます。このNumericクラスの追加は、組み込みの数値クラスに、ヤードポンド法の重さの単位を扱えるようにした拡張です。

class	Numeric
    def lb
        self * 453.59237 ;
    end
    def oz
        self.lb/16
    end
    def gr
        self.lb/7000
    end
end

print "#{124.lb + 4.oz}\n"
print "#{55.gr}\n"

 このあたりの自由度の高さが、Ruby信者が生まれる原因でもありますし、一方では厳密さを好むjavaの信者などには嫌われるところです。ウィザード言語万歳(w
(by yna)

一覧に戻る