凪瀬 Blog
Programming SHOT BAR

目次

Blog 利用状況
  • 投稿数 - 260
  • 記事 - 0
  • コメント - 46866
  • トラックバック - 192
ニュース
広告
  • Java開発者募集中
  • 経歴不問
  • 腕に自信のある方
  • 富山市内
  • (株)凪瀬アーキテクツ
アクセサリ
  • あわせて読みたい
凪瀬悠輝(なぎせ ゆうき)
  • Java技術者
  • お茶好き。カクテル好き。
  • 所属は(株)凪瀬アーキテクツ
  • Twitter:@nagise

書庫

日記カテゴリ

 

さて、その2の稿では取り漏らした str.equals("hoge")の意味の側面からとらえた「読みやすさ」に対する考察を行いましょう。

意味と合致するから分かりやすい?

さて、@ITではこのような意見がありました。(引用元)

自分は
if(str.equals("hogehoge"))
でなければ気持ち悪いです。
主語と動詞の関係があるわけですから、「strが"hogehoge"と同じか?」という意味と、「"hoghoge"がstrと同じか?」ではニュアンスが違いますからね。

思わず、なるほどと思う人も多いのではないでしょうか。しかし、実はこの理論には重要な欠点があるのです。

str.equals("hoge")の「意味」とは何か?

プログラムとして捉えた場合のstr.equals("hoge")の意味というのは冷徹で、

  1. 変数strに格納されたオブジェクトの
  2. equalsという名前で引数がString型のメソッドを呼び出し
  3. 引数には文字列リテラル"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)の意味を捉えるならば

  1. 文字列リテラル"hoge"の
  2. equalsという名前で引数がString型のメソッドを呼び出し
  3. 引数には変数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
コメント
  • # re: 文字列リテラルのメソッド呼出し その3
    シャノン
    Posted @ 2008/02/19 1:34
    > よくあるコードですね。さて、list.put(new Object())は、「listがObjectをputする」のでしょうか?

    ちゃいます。
    listにObjectをputさせるんです。

    > オブジェクトのメソッド呼出しを、オブジェクトを主語、メソッドを動詞、引数を目的語として対応付けようというのはそもそも無理があることなのです。

    そもそもが「Object」とは「目的語」という意味です。
    英語に倣えば、主語はthis、目的語がオブジェクト、あとは全部補語です。
    ちなみに動詞は have になります。

    ところで、このエントリの論旨は「読みにくいと思う理由は何であろうか?」であって、「別に読みにくくないよ」ということは言っていない、でいいですか?
  • # re: 文字列リテラルのメソッド呼出し その3
    凪瀬
    Posted @ 2008/02/19 2:05
    > そもそもが「Object」とは「目的語」という意味です。

    まぁ、その理論でいえば、引用部分の「主語と動詞の関係があるわけですから」は違いますね、で終わりなんですけどね。
    引用もとの意見はメソッド呼出しを主語、動詞、そして目的語として捉えていますよね。
    そして、「それに倣うとしたならば」という仮定で該当文章を読んでいただきたいと思います。
    そういう風に捉えにくい文章構成かなぁ…?

    > 「別に読みにくくないよ」ということは言っていない、でいいですか?

    この稿ではそういう主張はしていませんね。
    個人的には「読みにくくない」と思っていますが、「読みにくい」という人も実際にいることですし、
    そのように思う前提条件があると考えています。

    前提なしで「読みやすい」「読みにくい」のどちらかに結論付けることは事実を捉えていないと思いますね。
    特定の前提では読みにくい、特定の前提では読みやすい、といったものであろう、というのが私の考えですね。
    そして、その前提はなんであろうか、という点に関しては答えを出しきれていない。
  • # re: 文字列リテラルのメソッド呼出し その3
    myugaru
    Posted @ 2008/02/19 23:36
    こんばんわ。
    読みやすい読みにくいは人それぞれだと本当に思うんです。ちょこっと脱線しますと、昔々RPGはキャラクタが全てアスキー文字で表現されていました。Aが自分でXが敵とか!が武器とかです。

    想像を存分に膨らませるとそう思えてくるしそれはそれで別にその頃のPCスペックではそれ以上望むことが不可能だったので別に不自由だとか読みにくいとか思ったことはありませんでした。

    でも時代とともに人間の感性や尺度というのはどんどん進化してきました。いまだと誰もAとかXとかのゲームなんてやらないでしょう。時代は今Wiiなんでしょうからあれくらいのアウトプットを求めてます。

    str.Equals("hoge")というのも実際のところ私のようなふるい人間にはただの関数呼び出しにしか見えないです。逆に言えばこれが二つのものを比較しているように見える感性や尺度があまり発達してない、(あるいは私が進化しすぎてる?それは無いかな?)つまり私にはあまり合っていないのでしょう。

    私だったら読みやすいというのはstr == "hoge"でしょうしそれを内部でC#のLinqみたくstr.Equals("hoge")に翻訳してくれるのが言語コンパイラの役目じゃないの?くらいに贅沢なことも思っています。

    また関係ない事思い出しましたがC++の<<とか>>を入出力演算子に使った記述はC++を使い始めた頃案外読みやすいなって感心したことを思い出しました。
  • # re: 文字列リテラルのメソッド呼出し その3
    myugaru
    Posted @ 2008/02/19 23:42
    あ、つまりは自分は凪瀬さんの意見に賛同ですということです。長く書いてしまいました。(私わかりやすい文を書く練習しなきゃいけません。精進します><)
タイトル
名前
Url
コメント