プロトコルとインターフェースの比較

http://d.hatena.ne.jp/carver/20071202#p1

やっぱり両方を使っている人の意見は参考になる。
ただ、ここで指摘されている「interfaceとprotocolの違い」は、正確には「JavaObjective-Cの違い」ではないだろうか。また指摘されている違いは、「interfaceとprotocolの本質的な違い」と言えるだろうか。


以下、詳細。

定義できる要素
・インターフェース
   定数、メソッド、ネストしたクラスとインターフェース
プロトコル
   メソッド

インターフェースはクラス-2(インスタンスを生成できない、メソッドを実装できない)の機能を持つ。インターフェースと強く関連するクラスやインターフェースを、ネストすることで定義できる。
一方プロトコルはメソッドしか定義できない。Javaと異なり、ObjCのクラスとプロトコルは専用の変数・定数を持てない。もしプロトコルに定数を含めたい場合、その定数を返すようなクラスメソッドを宣言する。

2007-12-02

『専用の変数・定数』というのはクラス変数と、そのクラスで定義された定数という意味だと思うけど、そもそもObjective-Cにはクラス変数の機能がないし、定数もクラスに縛り付けることはできない。だからこれをもってinterfaceとprotocolの違いというのは違和感がある。正しくは「Javaの変数や定数とObjective-Cの変数や定数との違い」じゃないだろうか。

また『ネストしたクラスとインターフェース』というのはインナークラスのことだと思うけど、これも正しくは「JavaのクラスとObjective-Cのクラスとの違い」であって、「interfaceとprotocolの違い」と言われるのはすごく違和感がある。インナークラスのある・なしで「違う」と判断するなら、「JavaのクラスとObjective-C(だけでなくPHPとかRubyとかPythonとか)のクラスは違う」ということになる。でも普通は「クラスを定義できる点ではJavaObjective-Cも同じ」と言うはず。

型指定
Java:
   Comparable var;
・ObjC:
   id var;

インターフェースはクラスと同じように型として指定できる。
ObjCではプロトコルとクラスは別のもので、プロトコルを型としては指定できない。その代わりにプロトコルを指定する文法が用意されているので、id 型(オブジェクト型。JavaのObjectに相当)とプロトコルを指定する。上の例では ComparisonMethods プロトコルを実装したオブジェクトを宣言することになる。もっともObjCではクラスやプロトコルを指定する意味はあってないようなもので、間違ったら警告が出てラッキー、程度のもの。上の例のオブジェクトが本当にComparisonMethodsプロトコルに準拠しているかどうかはまったく保証されない。

2007-12-02

プロトコルを型としては指定できない』とあるけど、「id 」は型とはいわないのだろうか。型としての意味があまりないといえばそれまでだけど、それはprotocolのせいではなくて、基本的に型チェックを行わないObjective-Cのせいだろう。

だからこれも、JavaObjective-Cとの違い」「interfaceとprotocolの違い」じゃなくて「静的なJavaと動的なObjective-Cの違い」というべきじゃないだろうか。だってこれをもって「interfaceとprotocolは違う」と言いだしたら、やはり「JavaのクラスとObjective-Cのクラスは違う(型としての強制力が違うから)」となってしまい、それこそ「Java以前にclassなどというものは存在しなかった」というトンデモ理論になりそう。

名前
・インターフェース
   語尾はableで終わることが多い
プロトコル
   語尾がingで終わるか、名詞

上の例なら、比較メソッドを宣言したインターフェースはComparable、プロトコルはComparisonMethodsとなる。

2007-12-02

実はこの指摘は大変重要なんじゃないだろうか。もちろん命名方法の違いは機能の違いではまったくないけれど、概念や思想の違いを表してると思う。

その意味では、

インターフェースはクラスの性質に、プロトコルは振る舞いに注目しているらしい。
…(中略)…
・インターフェース名はそれを実装するクラスの形容詞になるのに対し、プロトコル名はオブジェクトの振る舞いを表すか(動名詞)、メソッドの集合を表す(名詞)。

2007-12-02

という指摘は興味深い。「性質」と「振る舞い」とどう違うんだと言われればそれまでだが(確かに「同じことじゃん」と言われたらそうかもしれない)。


・・・


というわけで、interfaceとprotocolの違いとして指摘された点は、「interfaceとprotocolの違い」ではなくて「JavaObjective-Cの違い」だと思う。変数や定数の扱いについては「Javaの変数や定数とObjective-Cの変数や定数との違い」だし、インナークラスが定義できる/できないというのは、そもそもの「JavaのクラスとObjective-Cのクラスの違い」であるし、型としての強制力の違いも「静的なJavaと動的なObjective-Cの違い」であると思う。どれも、「interfaceとprotocolの違い」というには強い違和感がある。


というか、これらの違いは「interfaceとprotocolの本質的な違い」といえるだろうか。例えばRubyのmoduleはJavaのinterfaceやObjective-Cのprotocolに似ているけど、Rubyのmoduleはメソッド定義を含めることができる(つまり実装の継承ができる)から、interfaceやprotocolと本質的に違うと言える。しかし、変数や定数の扱いとか、インナークラスが使えるかどうかというのは、interfaceとprotocolが本質的に違うと言えるだけの要素なのだろうか。


もしこういった論法が成り立つなら、そもそも静的な言語と動的な言語では同じ機能は存在しないことになる。「JavaのクラスとObjective-Cのクラスは同じ」と思う人なら、「interfaceとprotocolは同じ」と思うだろうし、「JavaのクラスとObjective-Cのクラスは違う」と考える人は「interfaceとprotocolは違う」というだろう(もちろん自分は前者である)。


…と批判的なことを書いたが、リンク先のエントリはJavaObjective-Cの両方をよく知っているからこそ書ける、いい内容だったと思う。もしinterfaceとprotocolの違いについて新しい発見があればぜひ書いていただきたい。というかもっと読みたいから書いてください。