ぶら下がりelse問題とは【Dangling else problem】

ぶら下がりelse

ぶら下がりelse(Dangling else)は、特定のif文に紐付くよう意図されていたelse文が、書き手の意図に反して異なる別のif文に紐付いてしまっている状態のことを言う。この状態によって引き起こされる問題は宙ぶらりんelse問題(dangling else problem)とも呼ばれている。人によってはdangling elseをダングリングポインタよろしく「ダングリングelse」と呼ぶこともあるため覚えておきたい。

if (!a)
    if (b)
        b();
else // ← ぶら下がりのelse
    a();

/* プログラム側ではこのように解釈されてしまう */
if (!a)
    if (b)
        b();
    else
        a();

ぶら下がりelseの問題は、フリーフォーマットを採用し、かつブレース(波括弧 = {})の省略が可能なC言語やJava, PHP, Perl, JavaScript等の言語で頻繁に発生する。オフサイドルールを採用して字下げのレベルに意味を持たせたPythonやCofeeScript等の言語ではこの問題は起こらない。またブレースの記述を必須とするSwiftやGo, Rust等の言語も同様にこの問題は起こらない。

目次

ぶら下がりelseの例

例えば、以下のelse文はif (!a)文に対応するelse文と思われるかもしれないが、実際にはif (b)文に紐付いたelse文と解釈されてしまう。

ぶら下がりelse状態の危険なコード

if (!a)
    if (b)
        b();
else
    a();

プログラミング言語側の解釈

書き手の意図に反してプログラミング言語側ではこちらの解釈が行われてしまう。

if (!a)
    if (b)
        b();
    else
        a();

このように、プログラムの書き手とプログラミング言語側で異なる解釈が生まれてしまうという厄介さがある。

以下のコードは両者の解釈の違いをブレースを用いて表現したものである。

/* 書き手が意図していた解釈 */
if (!a) {
    if (b)
        b();
} else {
    a();
}

/* プログラミング言語側の解釈 */
if (!a) {
    if (b)
        b();
    else
        a();
}

ぶら下がりelse問題の対処

if文ネスト時には、ブレース(波括弧)を適切に用いてブロック間の関係を明示する。これで ぶら下がりelse問題を回避できる。

if (!a) {
    if (b)
        b();
} else
    a();

理想は全ての文でブレースの省略を行わないようにすることである。この書き方なら ぶら下がりelseの問題はいかなる状況においても発生しないことが保証される。

if (!a) {
    if (b) {
        b();
    }
} else {
    a();
}

どうしてもブレース省略を活用したい場合には、「外側のブロックではブレースの明示を必須とする」といったコーディング規約を採用するとよい。

if (!a) {
    if (b)
        b();
    else
        c();
} else {
    a();
}

ただ、安全性を重視する現代のシステム開発では、ブレースの省略はあまり好まれないため注意して利用されたい。

ぶら下がりelseへの警告

現代のコンパイラは ぶら下がりelseを事前に警告してくれることがある。

if (!a)
    if (b)
        b();
else // 警告: Add explicit braces to avoid dangling else
    a();
このように ぶら下がりelseを回避するための明示的なカッコを追加するよう促される。

ただし、インタプリタ言語では依然警告されないものも多くあるため、ぶら下がりelse問題には引き続き注意しなければならない。

広告