さて、その2の稿では取り漏らした
str.equals("hoge")の意味の側面からとらえた「読みやすさ」に対する考察を行いましょう。
意味と合致するから分かりやすい?
さて、@ITではこのような意見がありました。(引用元)
自分は
if(str.equals("hogehoge"))
でなければ気持ち悪いです。
主語と動詞の関係があるわけですから、「strが"hogehoge"と同じか?」という意味と、「"hoghoge"がstrと同じか?」ではニュアンスが違いますからね。
思わず、なるほどと思う人も多いのではないでしょうか。しかし、実はこの理論には重要な欠点があるのです。
str.equals("hoge")の「意味」とは何か?
プログラムとして捉えた場合のstr.equals("hoge")の意味というのは冷徹で、
- 変数strに格納されたオブジェクトの
- equalsという名前で引数がString型のメソッドを呼び出し
- 引数には文字列リテラル"hoge"を渡す
というものです。
ところが、これを英文 "str equals hoge" と捉えたとするとその日本語訳は「strはhogeと等しい」となり、
まさにプログラムの意図するところと同じになるのです。
しかし、このことはプログラミング言語であるJavaで書かれたstr.equals("hoge")を
自然言語である日本語に訳した場合に「strはhogeと等しい」となることを意味しません。
Javaとしての正しい意味は先に挙げたとおりですが、その動きを総括して日本語で
「strはhogeと等しい」と捉えても「実用上はことたりる」というだけのことです。
プログラム言語を自然言語に翻訳できるのか?
プログラム言語と自然言語の間には大きくて深い溝があります。
str.equals("hoge")を「strはhogeと等しい」と捉えるのは危ういと言えるでしょう。
自然言語表現である「strはhogeと等しい」は当然ながらNullPointerExceptionを発生させません。
自然言語表現「strはhogeと等しい」のJava言語への翻訳としては
(1) str.equals("hoge")
(2) str == "hoge"
の二つが考えられます。プログラム言語でいうところのこのふたつの違いははっきりしていますが、
自然言語でのこの違いは曖昧です。言葉としての表現にはこのような違いは自然には載らない。
だから、その「意訳」を読み手であるプログラマがするのだし、要件定義においては、この曖昧さを
プログラム言語的な厳密さにするために、えらく小難しい言い回しにしてしまう。
「strのオブジェクトと"hoge"の内容を比較する。strがnullのときはNullPointerExceptionをthrowする」
ただし、「実用上はことたりる」と表現しました。こういった厳密さが求められるシチュエーションは少ない。
大抵の場合は「strはhogeと等しい」という意味に捉えていれば事足りる。
そして、str.equals("hoge")という表現はこの「strはhogeと等しい」という捉え方を喚起しやすいと言えるでしょう。
同じく自然言語である英文であるところの"str equals hoge"に変換して捉えることでそれはなされる。
equalsの挙動を理解するための便法
「strはhogeと等しい」では、オブジェクトを主語、メソッドを動詞、引数を目的語として捉えているのですが、
これはequals以外でも成り立つのでしょうか?
別の例を挙げましょう。よく使われるjava.util.Listを取り上げたいと思います。
List list = new ArrayList();
list.put(new Object());
Object o = list.get(0);
よくあるコードですね。さて、list.put(new Object())は、「listがObjectをputする」のでしょうか?
違いますね。「listにObjectをputする」あるいは「Objectをlistにputする」と捉えますね。
list.get(0)は「listが0をgetする」のでしょうか?
違いますね。「listから0番目のオブジェクトをgetする」あるいは
「0番目のオブジェクトをlistからgetする」と言うのではないでしょうか?
オブジェクトのメソッド呼出しはオブジェクトを主語としない一例でした。
このことからも分かるように、「strはhogeと等しい」というのは便法(べんぽう、便利な方法)という奴で
プログラムの解釈としては正しくないけども、equalsメソッドに限って言えばそのように捉えることで
意味を把握できる便利な方法なわけです。
str.equals("hoge") → "str equals 'hoge'"という英文 → 「strは"hoge"と等しい」という日本語
という便法を利用している場合、"hoge".equals(str)に適用すると
"hoge".equals(str) → "'hoge' equals str"という英文 → 「"hoge"はstrと等しい」という日本語
となってしまいます。
そして、自然言語のうち少なくとも英語や日本語では定数を主語にとって変数と比較するということはしませんから、
日常我々が使っている自然言語の文脈としては奇異なものになります。
そしてそれは確かに仕様書などで使われる自然言語表現とは食い違う。
それが「読みにくい」と感じる理由ではないでしょうか。
便法を用いずに意味を捉える
プログラムとして"hoge".equals(str)の意味を捉えるならば
- 文字列リテラル"hoge"の
- equalsという名前で引数がString型のメソッドを呼び出し
- 引数には変数strに格納されたオブジェクトを渡す
となります。そして、これはstr.equals("hoge")と明らかに違う。
しかし、われわれプログラマはこれを「同じ」と捉えます。なぜでしょうか?
AをBと比べるのと、BをAと比べるのでは「アルゴリズム的には同じ」と捉えますね。
つまり、「足し算の順序を入れ替えても結果は同じ」というのと同様に「交換法則」が成り立つことを
経験上理解しているわけです。
NullPointerExceptionの発生しない条件下では、このふたつの記法の示す「アルゴリズム」は同じなわけです。
このような捉え方をしていた場合、「"hoge"のequalsメソッドにstrを渡すとどのようなことが起こるのか」という
場合の挙動を考えることは不自然ではありません。オブジェクトはメソッドを持つ。
変数strにはオブジェクトが格納されるし、文字列リテラル"hoge"もオブジェクトです。
ですから、strのequalsを呼ぶことも、"hoge"のequalsを呼ぶこともなんらの違いはない。
自然言語との溝
プログラム言語も自然言語も「言語」と付きますが、しばらく思想をめぐらせれば
その翻訳の試みは儚くも崩れ去ることでしょう。
オブジェクトのメソッド呼出しを、オブジェクトを主語、メソッドを動詞、引数を目的語として対応付けようというのは
そもそも無理があることなのです。
equalsのような例では、たまたまうまく当てはまるだけの例外的な事例で、特殊な便法だと捉えるべきです。
この項で提唱した説は「便法によってequalsの動きを捉えている場合、
自然言語にひきずられて定数のメソッド呼出しが奇異なものと感じられるのではないか?」というものでした。
ここで確認しておきたいのは、"hoge".equals(str)を奇異に思う人全てが便法による意味解釈をしていると
主張しているわけではないということです。
ただ、このように人間の思考のアルゴリズムを考えることは、
物事を理解する、あるいはさせる場合の一助となるのではないでしょうか。
投稿日時 : 2008年2月19日 1:05