プログラミング/ダックタイピング
ダックタイピングは、Rubyコミュニティに属するDave Thomasによる造語で、
"If it walks like a duck and it quacks like a duck, then it must be a duck" (アヒルのように歩き、アヒルのように鳴くなら、それはアヒルに違いない)
というダック・テストに由来する。
ダックタイピングは、Smalltalk・Ruby・Python・JavaScriptやLuaなどのプログラミング言語でよく見られる動的型付けの一種であり、変数の示すオブジェクトがその変数に対して実行可能な操作を決定する。
例
[編集]これはRubyにおける簡単なダックタイピングの例で、どのようなオブジェクトも、それがサポートしていない方法で使われるまでは、どのような文脈でも使うことができることを実証している。
- コード
class Duck def swim() puts("Duck swimming") end def walk() puts("Duck walking") end end class Whale def swim() puts("Whale swimming") end end [Duck.new, Whale.new].each do |animal| animal.swim() animal.walk() end
- 実行結果
Duck swimming Duck walking Whale swimming
- 実行時エラー
Main.rb:12:in `block in <main>': undefined method `walk' for #<Whale:0x00001551f91f0ff8> (NoMethodError) animal.walk() ^^^^^ from Main.rb:10:in `each' from Main.rb:10:in `<main>'
この通り、アヒルは泳げるから、泳げるものはすべてアヒルだとすると、クジラはアヒルとみなされる。しかし、陸を歩けることも条件とすると、クジラはアヒルとはみなされない。
静的型付け言語において
[編集]BooやD言語などの静的型付け言語では、クラスの型チェックはコンパイル時ではなく、実行時に行うように指定することができる。
他の型システムとの比較
[編集]記名的型付け
[編集]記名的型付け(nominative typing)では、オブジェクトがある型であると宣言されている場合(あるいは、オブジェクト継承などのメカニズムによって型とオブジェクトの関連性が推測される場合)、そのオブジェクトはある型であるとされる。 ダックタイピングでは、オブジェクトは、その型が要求するすべてのメソッドとプロパティを持つ場合、与えられた型のものである。 ダックタイピングでは、与えられたオブジェクトと型の要求の間の使用ベースの構造的等価性と見なすことができる。
構造的型付け
[編集]ダックタイピングは、構造的型付け(structural typing)と似ているが別物である。 構造的型付けは静的型付けシステムで、型の構造によって型の互換性と等価性を決定する。 これに対象して、ダックタイピングは動的で、型の構造のうちランタイムにアクセスされる部分のみによって型の互換性を決定するものである。
プロトコルとインターフェース
[編集]プロトコルおよびインターフェースは、いくつかのメソッド、演算子、または動作を定義する必要があることを明示的に宣言する方法を提供する(例えば、quack()メソッドを持つ必要があるなど)。 サードパーティのライブラリが変更できないクラスを実装している場合、そのクラスが実際にはインターフェースの要件を満たしていても、クライアントはそのライブラリが知らないインターフェースでそのインスタンスを使用することができない。 この問題に対する一般的な解決策はw:Adapter パターンである。一方、ダックタイピングの下では、アダプタを必要とせず、オブジェクトを直接受け入れることになる。
テンプレートまたはジェネリック
[編集]テンプレート、またはジェネリック関数やメソッドは静的型付けのコンテキストでダック・テストを適用する。 これは一般に静的対動的型検査のすべての利点と不利点をもたらす。 またダックタイピングは、実行時に実際に呼ばれるメソッドのみを実装すればよいという点でより柔軟であるが、テンプレートは到達できないことが証明できないすべてのメソッドの実装を要求する。
Java、Scala、Objective-Cなどの言語では、リフレクションを用いてオブジェクトがメソッドを実装しているかどうかを調べたり、実行時に必要なメソッドを追加したりすることもできる。
例えば、Java の MethodHandle API はそのような使い方ができる。