else {//何もしない}を書くべきか?具体例と考察


(最終更新日:

記事イメージ

先般、Twitterを中心にelse {//何もしない}は必要か否か?という議論が若干の盛り上がりを見せました。圏論的思考論、パターンマッチング、そしてプログラミング実務家も入り乱れ議論は混迷の様相でした。

個人的にも議論の行く末が気になっていたところ、この議論を踏まえてその後コーディングしていて気づいた点があったので、実例を交えて私見をまとめてみることにします。

尚、題材の議論は具体的には、以下の例のようにelseでやることがない場合で「else {//何もしない}を書くべき/いやいやこんなん不要やろ」といった具合です。


if (hoge == 0) {
    //trueの場合に必要な処理
    hoge += 1;
    hoge += 1;
} else {
    //何もしない  ←elseで何もしない場合でも、else句を書くべき?それとも邪魔なだけ?
}

※筆者はプログラミング実務家であり数学者ではありません。ですので数学的議論は含まず実務家目線で論じます。用語の使用が変な可能性がありますがご容赦ください。

※else {//何もしない} は、Pythonにおける else: passなど、言語仕様として組み込まれている場合があります。

結論:場合による。暗黙的にパターンマッチを行ってもよい。

「要は場面次第であり、可読性の観点でelse{//何もしない}があった方がよい場面がある」、「パターンの存在を明示する必要がある場合にelse{//何もしない}があると良い」というのが私的な(現段階での)結論です。

コードが煩雑化するデメリットと天秤にかけ、暗黙的にパターンマッチを示す(else {//何もしない}を省略する)ケースがあっても違和感はありません。ですので、要/不要の二元論でとらえるべきではないだろう、と考えています。

具体例を示しながら、検討していきます。

else {//何もしない}が不要と思われるケース

例えば以下のように処理中に早期リターンするといった用途でのifは頻出です。


bool run(string? hoge) {
    if (hoge == null) {
        return false;
    }
    //正常処理
    //(前段のifは早期リターンの意図が明確。
    //そのためあえてelse句で正常処理をくくったりはしない)
}

このケースでは「早期リターンする」という実装者の意図が明確に見えるため、あえてelse句を使用する必要はないでしょう。使用すればネストが深くなりむしろデメリットの方が大きくなるように感じます。

尚、こういったelseの省略を行っていても、意味的には「処理を実行するべき引数か?」「処理を中断するべき引数か?」のパターンマッチを暗黙的に行っていると言えます。

【社内PR】チーム・ウォーク

else {//何もしない}を書いた方がよいケース

逆にelse {//何もしない}を書くべきケースを検討していきます。

前述した通り、コードのレビュワーやコードを読む他者・後の自分に対して、処理パターンの存在を明示することが主な目的です。

例えば次の例のように、処理の種類ごとに返すページ変数取得経路をスイッチする場合を考えます。(UIからのユーザー指示により遷移するページを分岐する場面を念頭に置いています。)


//Http Postアクションに対するレスポンスを行う関数
Action ResponseToUserPost(string userPostCommand, int? pageNo) {
    //検索条件を格納する変数
    var searchCondition = "";

    if (userPostCommand == "ChangePage" && pageNo != null) {
        //ページ変更かつユーザーからのページ番号指定がある場合、リダイレクトしてそのページを返す
        return Redirect(pageNo: pageNo);
    else if (userPostCommand == "ChangePage" && pageNo == null)
        //ページ変更かつユーザーからのページ番号指定がない場合、リダイレクトして1ページ目を返す
        return Redirect(pageNo: 1);
    } else if (userPostCommand == "QuickSearch") {
        //クイックサーチの場合、クイックサーチ用の検索条件を取得
        searchCondition = _getQuickSearchCondition();
    } else if (post_command == "DetailSearch") {
        //詳細検索の場合、詳細検索用の検索条件を取得
        searchCondition =  _getDetailSearchCondition();
    } else {
        //何もしない
        //(いずれのパターンにもマッチしない場合、検索条件なしで一覧を返す。
        //あえて処理を書くなら、searchCondition = "";と処理しても良い。)
    }
    
    //検索して結果を表示する
    var searchResult = RunSearch(searchCondition);
    return View(searchResult);
}

このケースにおける一連のif-else句は、ユーザーの入力内容を解析して、どのパターンを実行するべきか(簡易検索か?詳細検索か?ページ番号推移か?)を分岐して処理を振り分けています。

いくつかのifはそのif句内部でreturnしていないものもあり、いずれのifにマッチしなかったケースも、一つの実行パターンとして存在(この例でいうと検索条件なしで一覧を返すというパターン)しています。

そこでそのケース(いずれのifにもマッチしない実行パターン)の存在を明示するため、「else {//何もしない}」があった方がベター、となるわけです。

(パターンマッチを入出力機能を持つ箱と捉えるならば、入力はifに掛けられる変数、出力は「if句がスコープ内の変数に及ぼす作用の内容」といったところでしょうか。)

ここまでのまとめ:なぜelse {//何もしない}を書くのか?

以上を取りまとめ、なぜelse {//何もしない}を書くのか?の回答を書いてみます(繰り返しますがあくまで私見です)。

全般的に言えるのが「見る人に対する配慮」が主な理由となります。よって、逆にその様な配慮が不要なほどコードが単純なケース(例えば単純なif+elseパターンでelseifを含まないような単純なifブロック)ではあえてこのような記法をせずコードの簡略性を優先しても良いと考えます。

なぜelse {//何もしない}を書くのか?
  • 一連のif-elseブロックで、どのようなパターンを想定しているのか?を示す。これにより、何もしなくてよいパターンがあったとしても「何もしない」場合のパターンの存在を明示する。
  • 一連のif-elseブロックが、後続処理にどのような影響を与えるのか示す。これにより、何もしない(後続処理に何も作用しない)ケースが存在していることを明示できる。

考察:ifはswitchと違いdefault句がない言語が多数派のため、議論を呼ぶ

これは単に考察ですが、switchはdefault句が強制されるためこのような議論は起きませんが、ifの場合はそうでない(ifにdefaultがない)言語仕様が多数派です。

そのため何も意識せずelseなしifを書いてしまいがちであり、その中には上述のように「いずれのifにもマッチしない場合は何なのだ?考慮漏れか?この一連のifで実現したかったのは何なのか?」という疑問をレビュワーに抱かせるものが生じます。

実務論的には、ネストが深くなるデメリットも考慮して、「いずれのifにもマッチしないケースは何か?」が明示するべき場面かどうか?を意識していけばよいでしょう。

*2022/11/20 コメントをいただきまして、上記取り消し部「switchはdefault句が強制」という言語仕様については誤認であることがわかりました。大変失礼しました。この新たな知識をベースに↓セクションを追加しました。コメントを頂戴したyuki様、誠にありがとうございます。

switch文におけるdefault句の取り扱いについても考え方は同じ(2022/11/20追加)

switch文はif文と同様に条件分岐を実装することができ、default句を必須とするか否かという同種の議論が生じさせます。ただ、switch文の場合であっても基本的な考え方は変える必要がなく、パターンマッチの可視性の観点でdefault句を書くか否かを検討すればよいと考えます。

簡単な例で考えてみます。month(月)というint型の変数でSwitch文を使用しています。1月、4月、7月、10月の時だけ処理を実行する意図でコードが記述されています。逆に左記以外の月では実行するものがない状態です。

ここでdefault句をあえてつけている意味は何でしょうか?処理的には何も変わりませんが、「month=1、4、7、10以外のケースが存在し得ること」、「1月、4月、7月、10月以外では実行するものがない」ということをコードの読み手に伝えるのに効果的と言えます。

下記例のように、default句にあえてケースの列挙などを示してみるとより親切といえるでしょう。


int month = GetMonth();

switch (month) {
    case 1:
        JanProcess();
        break;
    case 4:
        AplProcess();
        break;
    case 7:
        JulProcess();
        break;
    case 10:
        JulProcess();
        break;
    default:
        //case: 2,3,5,6,8,9,11,12 -> Do nothing
        break;
}

閑話休題。「そもそもそんな長たらしいif文書くのってどうなの?」という意見

今回のように「else {//何もしない}が必要になってしまう、あまりに長いif句」が出来てしまうのは、実は網羅的パターンマッチ機能(switch句)を使うべき場面である、ということ以外に関心の分離が不十分である可能性があるように思います。

ポリモーフィズムを用いたりしてクラスや関数を関心毎に適切に分離していくと、自然とifを書く回数が減っていき、コードが簡潔になっていく様子が見て取ることが出来ます。

詳細については、(関連記事)【関心の分離/責務の分離】変更に強いプログラミング実践手法にて解説しています。近隣の話題になりますので、是非合わせてご参考ください。

記事筆者へのお問い合わせ、仕事のご依頼

当社では、IT活用をはじめ、業務効率化やM&A、管理会計など幅広い分野でコンサルティング事業・IT開発事業を行っております。

この記事をご覧になり、もし相談してみたい点などがあれば、ぜひ問い合わせフォームまでご連絡ください。

皆様のご投稿をお待ちしております。

記事筆者へ問い合わせする

※ご相談は無料でお受けいたします。

この記事へのコメント

yuki

とてもわかりやすくて良い着眼点の記事かと思います!

本題からずれるのですが、
>switchはdefault句が強制されるため

とありますがdefaultが強制される言語って何がありますか?

筆者(堺)より返信

yuki様、コメントありがとうございます!嬉しいお言葉、励みになります。

すみません、Switch文の実装に誤認があったようでした。少なくともC-like syntaxの言語ではdefault句は省略可のようですね。
該当の箇所を修正しました。ご指摘誠にありがとうございます。

ニックネーム(任意)

返信通知先Emailアドレス(任意)

本文


* 感想やご意見等、お気軽にコメントください。但し、公序良俗に反するコメントはお控えください。
* 管理者が承認したコメントはこの箇所に公開させていただく可能性がございます。
* 返信通知先Emailアドレスは、筆者のみに通知され、公開されることはありません。返信通知先Emailを入力された場合は、コメントへの返信をこちらに掲載した際に通知させていただきます。その他の目的には使用いたしません。
* スパム対策のため、コメントは日本語のみ受け付けております。

堺財経電算合同会社 小規模IT構築サービス