Home日記コラム書評HintsLinks自己紹介
 

フィンローダのあっぱれご意見番 第151回「何かの参考のために」

← 前のをみる | 「フィンローダのあっぱれご意見番」一覧 | 次のをみる →

Webを日常的に使うようになると、 何か調べたいときにに、書籍ではなくまずWebを、という生活になってくる。 書籍を読めば、何をすればどうなるか、ということが分かる。 Webで発見できるのは、 どうすればよいか分からないときに何をすればよいか、ということだ。 トラブルの状況を、 例えばエラーメッセージやエラーコードをキーワードに指定して検索できるのは、 なかなか便利なものである。 世の中には「私はこんなドジをやりました」と紹介してくれるありがたいページがわんさかあって、 運がよければ、どうやって解決できるかまで分かるのだ。 まあ運次第ではあるが。

私も、失敗したら「ネタが出来た」と喜んで公開してしまうタイプだ。 失敗談というのは、自分がもう一度失敗したときの役にも立つ。 私自身、 何か分からなくなって Google で検索したら自分のサイトがヒットしたことが何度かある。 同じ過ちを何度も繰り返すのは誉められた話ではないが、 日常的に繰り返していることならともかく、 何年かに一度発生するようなトラブルは忘れてしまうものだ。 それに、繰り返すといっても、一度解決した経験があれば、 思い出してからの処理は早いものである。 全てを記憶するよりも、ちょっとだけ覚えておいて、後は何かあったらWebで検索できる、というのは素晴らしい方法ではないか。

Webで公開しておけば、誰かが何かあったときに参考になるかもしれないし、 そういう発想の人が大勢いれば、威力は爆発的に増大するというものだ。

§

ふ「今回は三項演算子の話を書きたいと思います。」

  

U「そういうタイトルでしたか。」

 

※ 蛇足だが三項と参考をかけている訳だ。

ふ「という訳で、実はやっちゃいましたが、ブログ見てくれた人はありがとう。 ブログでは、あんなのを雑誌に書くと雑誌間戦争になるのではというような内容も書いたりしていますが、流石にここでは控え目に書くのです。」

 

※ブログというのは 裏表のこと。 やっちゃったというのは、 Java World の記事に対するもので、2004年10月30日の、 あまり特殊なテクニックは使わないあまり特殊なテクニックは使わない (2)を指している。

U「ターゲットがCマガジン内の記事ならヤッてしまいそうな気が…。

  

ふ「まあ昔は若かったし。ということで、 今回はchatでも紹介したようなことを書きたいのです。

 

※ Cマガジンの他の記事を見て疑問に思ったことを、 本コラムに書いたことがあった。 そのことを「昔は若かった」と言っている。 もっとも、掲載前に著者に連絡を取ったのだが。 三項演算子の話は、掲載前に FPROGORG の chat で話題になっていた。

U「ネタは殆どchatで出てしまったのですが、書くと言ってしまったし、 とりあえず、 まとめるつもりで行ってみましょう。

ふ「まず、三項演算子を知らないとか、知らない人がいるとか、見慣れない、というのは言語道断なので無視することにして、いい使い方の例を紹介します。 Java のつもりですが、何の言語かはあまり気にしないでもいいはずです。 場合によっては C でも可。

  
---- List 1 (三項演算子を使った return 文) ----

    return (value < 0) ? false : true;
 

※ だったら return value >= 0; で済むのでは、 と突っ込まれたのだが、そう言われればそうだ。 まあここは三項演算子の説明のための例なので。

U「value < 0 という式の両側の括弧は必要なのですか?

ふ「優先順位だけを考えると必要ありませんが、 ここはゲシュタルト心理学的に意味があるので付けても構わないと思います。 さて、これを if を使って同じ意味になるように書き直してみてください。

U「こうですか。(List 2)

---- List 2 (if を使って return する) ----

    if (value < 0) {
        return false;
    } else {
        return true;
    }

ふ「とりあえず、まあいいでしょう。

U「何と! とりあえずなのですか。

ふ「私の採点では、その回答だと95点です。 次の問題は、List 1 と List 2 の2つの書きかたに対して、 それぞれの意味を考えてください。

U「え、同じ意味ではないのですか?

ふ「動作は、たまたま同じになっていますが、 単純に理解すれば意味は違うはずですよ、 実はその「単純に理解すれば」という所が可読性を大きく左右することになります。 意外と重要な話なのです。

U「そういうものですか。 えーと、まず List 1 は、valueの値が負のときはfalse、そうでないときはtrueを返す。

ふ「ist 2 はどうですか。

U「valueの値が負のときは、falseを返し、そうでないときはtrueを返す。

ふ「微妙な違いは分かりますか?

U「三項演算子を使った場合は“返す”という言葉が一度しか出てこない、 なぜなら、この行全体は return 文になっていて、何か値を返すことが確実だからです。 言い換えれば、return するということが全体を縛っている。 これに対して、if を使った場合は、それぞれの場合に対して何かをするという構造になっています。 何をするかは読んでみないと分かりません。 つまり、 この後、条件が成立しようがしまいが、何か値を返してメソッドは終了するのですが、 条件を読んだだけではそのことは分かりません。

ふ「解説としてはそんな所ですね。 もっと単純に“読む”とどうなりますか。 例えば、 List 1 を左から普通に読めば、 return する(…ということは、何か値を戻して終わるのか、何を戻すのだろうか)、valueが0より小さいと、false、そうでない場合は、trueを。という感じで頭の中で考察していることになります。()内は独り言です。

U「なるほど、if の場合は、まず、valueが0より小さい場合は、false を戻して処理終了、 そうでないときは、true を戻して処理終了。 あれ、意外と簡単ですね。

ふ「三項演算子を使って書くと、常に何かを戻すのだ、という束縛条件がありますから、その分、表現は複雑になるのです。 三項演算子が分かりにくいという人がいますが、 おそらくそのあたりが影響するのでしょう。

§

ふ「では、if を使って、確実にこのメソッドから返るのだ、ということを表現するように書き直してみてください。

---- List 3 (if を使って戻り値を決める) ----

    boolean returnValue;
    if (value < 0) {
        returnValue = false;
    } else {
        returnValue = true;
    }
    return returnValue;

U「こうですか。(List 3) しかし、ここまで書くかなぁ、実際に。

ふ「まあこんなコードはまず書かないですね、 List 2 のように書いた方が分かりやすい。 ただ、リファクタリング時の不安は残るかもしれない。 もちろん、三項演算子使えば簡単に書けるのだし。

§

ふ「では、次は List 4 を if を使って書き直してみてください。

---- List 4 (三項演算子で値を決める) ----

    int a = (value < 0) ? -value : value;

U「こうですか…」

---- List 5 (if で値を割り当てる) ----

    if (value < 0) {
        a = -value;
    } else {
        a = value;
    }

ふ「さっきの考察はどこに行きましたか?

U「それを説明しますとですね、確かにこう書くことはできますよ、

---- List 6 (if で割り当てる値を割り当てる) ----

    int nonNegativeValue;
    if (value < 0) {
        nonNegativeValue = -value;
    } else {
        nonNegativeValue = value;
    }
    a = nonNegativeValue;

U「しかし、流石にこれってかなりバカなことをしているような気が…。

  

ふ「確かに、猫も杓子定規って感じはしますね。 これはこれでいいことにして、次はこんなのはどうでしょうか?

 

※ そんな諺はない。

---- List 7 (三項演算子で場合分け) ----

    (value < 0) ? a = -value : a = value;

U「こんな感じですか? (List 8)

---- List 8 (if で場合分け) ----

    if (value < 0) {
        a = -value;
    } else {
        a = value;
    }

ふ「そうですね、多分そういう意図で書いたのだと思います。 私はそういう書き方をしないので、意図がよく分かりませんが。

U「多分というのは?

ふ「三項演算子の特徴は、その結果の値が得られるという所にあります。 第1項で単純に条件判定して、第2項と第3項で別の処理をさせる、というのであれば、 三項演算子としての特徴は失われて、 if と同じになってしまうのです。

U「その値というのはどこに行ったのでしょう?

ふ「そりゃもう激しく気になりますよね、 そういう書き方はプログラマーの心を乱すので、 List 7 のような書きかたは、特別な理由がない限り、 しない方がいいと思います。

U「結論としては、三項演算子は、条件によって異なる値を得て、その結果を return したり、代入したい場合に用いる。結果の値を使わないのであれば、if を使って書く。ということですか。

ふ「経験的にはそれが一番 readability がよくなると思います。 もちろん、readability には個人の趣味が多大に影響するので、 書ける場合にはどんな場合も三項演算子がいいという人とか、 三項演算子は使ってはいけないとか、 いろんな極端な人はいますけど。

§

U「ところで、ゲシュタルト心理学というのは?

ふ「一言でいうには誌面が足りないのですが、 今回は、括弧でくくったものは一つの塊として認識される、という法則を指しています。 fig. 1 を見てください。

---- fig. 1 (括弧でくくると塊になる) ----

    aa  bb  cc  dd  ee  ff

   (aa  bb)(cc  dd)(ee  ff)

ふ「fig.1 の上側の行は、単に6つのブロックがあるように見えますが、 下側の行を、大抵の人は(aa bb)というブロック、 (cc dd)というブロック、 そして、(ee ff)のブロック、 合計3つのブロックとして認識します。 なぜ人間がこのように認識するのか解明しようというのが、 ゲシュタルト心理学という学問です。

U「パッと見た感じだけでも、普通にそう認識しそうなものですが、何か罠がありますか?

ふ「括弧を使っているというのがポイントです。 括弧ではなく「%」を使ってみましょうか。 どう見えますか?

---- fig. 2 (括弧でないものを挟む) ----

   %aa  bb%%cc  dd%%ee  ff%

U「あれ、%aa、bb%%cc、dd%%ee、ff%、の4つのブロックに見えるなぁ、何故だろう?

ふ「それを説明しようというのがゲシュタルト心理学です。 括弧使うと、括弧の中が一つのグループとして認識されるようになり、 うまく使えば可読性は増えます。 ただ、普通に読んでも一つのブロックになるような状況で括弧を多用してしまうと、 かえって情報過多になったり、あるいは、括弧が多数あることで括弧のパワーが落ちてしまって、かえって可読性を低下させる危険もあります。 今ではこういう書き方しないと思いますが、

---- List 9 (括弧の価値がない例) ----

    return (1);

ふ「この括弧はあっても見やすくなるわけではなく、逆効果かもしれません。 三項演算子の場合は、各項の区切りが分かりにくくなりがちなので、 括弧を付けた場合の効果は比較的高くなります。 優先順位があるから必要ないといって、括弧を全て省略してしまうのはよくないのです。

  

(C MAGAZINE 2005年1月号掲載)
内容は雑誌に掲載されたものと異なることがあります。

修正情報:
2005-04-01 注釈追加版を公開。
2005-04-04 注釈追加。
2006-03-01 裏ページに転載。

(C) Phinloda 2005-2006, All rights reserved.