なにかと嫌われ者のgoto文ですが、周りが悪いと言ってるから悪い物と決めつけるのもいささか問題があります。本記事ではgoto文の概要を説明するとともに、goto文がなぜ良くないのか・禁止するべきなのかを検証していきます。
目次
- goto文とは
- goto文 不要論
- 処理の流れや値の変化が読み取りづらくなる
- goto文はプログラマの負担になる
- 禁止したほうが手っ取り早い
- goto文には制限が必要
- goto文の代替機能が増えている
- 「goto文は悪」という世間の評価について
- goto文は教養
goto文とは
goto文(goto statement)は処理を指定の位置へと移動させるための制御文です。goto文はジャンプ文の一種であり、同様のジャンプ文には他にreturn/break/continue文が存在します。
int main() {
goto label; // 3行目の`label:`へ移動する
printf("a"); // 実行されない
label:
printf("b"); // 実行される
}
goto文を利用するとプログラム中の様々な位置に処理を自由に遷移させることが可能になります。しかしその分処理の流れが追いづらくなり、読みづらいコードを生んでしまう危険性があります。
int main() {
goto B;
A: printf("a"); goto C;
B: printf("b"); goto A;
C: printf("c");
}
出力結果: bac
変数の状態によってgoto文の遷移先が変化するような処理を書いてしまうとさらに複雑なコードとなり、処理の状態を把握することが困難となります。
int main() {
int v = 0;
goto B;
A: printf("a");
if (v > 2) goto C;
B: printf("b");
v += 1;
goto A;
C: printf("c");
if (v < 4) goto B;
}
出力結果: bababacbac
goto文はこのように複雑で理解のしづらいコードを生み出しやすく、現在ではgoto文は有害な物として認知され、使用を禁止する動きが主流となっています。
goto文 不要論
プログラミング業界ではgoto文は有害な物とされており、goto文の利用そのものを禁止する開発現場も多く存在します。多くのプログラミング入門書や教育現場でもgoto文は使うべきではないと説明されています。
ただ、実際にgoto文が「どれほど危険なのか」「どのように悪いのか」の部分はあまり示されていないように思います。「処理が複雑になるから」といった説明や「保守が大変になるから」程度の簡潔な説明に終始することがほとんどなのではないでしょうか。
本記事ではgoto文が危険だ/不要だと言われる理由やその根拠を探っていきます。
処理の流れや値の変化が読み取りづらくなる
従来のプログラムの処理というのは上から下へ順番に流れていくものですが、goto文を使用してしまうと、この流れが不規則になってしまいます。突然別の処理に飛んでしまったり、同じ処理を何度も通ってしまうようなことが起こってしまうわけです。
if/for文でも同じだが規則的
for文やif文を使っていても同じようなことは起きますが、あくまで規則的・限定的であり、精々1→2→3→4
という処理の流れが1→2→4
や1→2→1→2→3→4
になる程度です。基本は一方向に向かって処理が流れていきます。
goto文は処理の流れが変則的
goto文を使ってしまうとこれが4
から急に2
に飛んだり、または逆方向に処理が進んでしまったりと、非常に変則的な順序になりやすくなります。複雑な迷路のようなコードを作ってしまう可能性がでてくるわけです。
処理パターンの把握が困難
使用するgoto文が増えれば増えるほど、道のパターンも増えていくわけですが、それら全てのパターンを把握することは大変困難です。
また変数の値もそれらのパターンごとに異なるタイミングで更新されていきますから、変数の値変化のタイミングもまた把握しづらくなるでしょう。また変数の値の状態によってgoto文の遷移先が変化するような処理を書いてしまうと更に複雑で厄介な処理になってしまいます。これはコードの保守性にも悪い影響を与えることになります。goto文が引き起こすこれらの複雑さはプログラムの不具合やバグに繋がる危険性もあります。
goto文はプログラマの負担になる
これらgoto文のデメリットや危険性はある程度注意をしていれば回避できるのですが、この「注意する必要がある」という点が曲者なのです。特にプログラミングスキルが低いプログラマや、goto文への理解が低いプログラマ、右も左も分からない初心者は、先程説明した様々な問題を引き起こしやすくなります。
つまるところgoto文にはプログラマの経験や注意力が過剰に求められてしまうという欠点があるのです。またこれらは使う側の負担やストレスにもなります。
禁止したほうが手っ取り早い
このようにgoto文の効果は使い手の力量に依存しやすいという特徴があります。上級者が使うとそれなりに安全でまた効果的なコードにもなるのですが、初心者が使うと危険なコードになりやすいのです。
こと複数人開発におけるプログラマ達の力量にはバラツキがつきものです。するとgoto文のこれらの特性は、システム開発という名の共同作業においては大きなリスクにもなり得ます。このようなリスクや危険性を排除するためには、goto文の利用自体を禁止するのがもっとも手っ取り早い解決策となることでしょう。
goto文には制限が必要
goto文自体は注意して利用すれば問題が起きづらいのですが、問題が起きないように意識したり使い方を制限しなければならないという点がgoto文不要論を必要以上に後押ししているように思えます。
ただgoto文を有効に活用できる分野もあるため、状況に応じて使うという選択も必要なのではないかとも思います。多重ループの一斉脱出やリソース解放などがその良い例でしょう。
goto文の活用例と代替案 - 多重ループの脱出
goto文の活用例と代替案 - リソース解放
goto文の代替機能が増えている
ただ最近ではgoto文を使わなくても同様の処理を実現できるような仕組みやテクニックも多く出てきており、goto文の必要性は徐々に減ってきているというのが現状です。またgoto文を言語機能として取り入れない言語も多く登場しています。
goto文の代替機能
- ラベル付きbreak
- defer文
- デストラクタ
- 例外機構(try-catch-finally等)
- cleanup属性(コンパイラ拡張)
goto文の代替テクニック
- do-while-falseイディオム
- フラグによる脱出判定
gotoを取り入れていない言語
- Python
- Ruby
- Swift
代替機能に関するより詳しい説明は以下の記事が参考になります。
goto文の活用例と代替手段 回避策【多重ループ脱出 リソース解放 関数化回避】
「goto文は悪」という世間の評価について
現在の「goto文は悪」という世の中の風潮は、「刃物は危険だから扱いに注意しよう」というよくある常識とは少し次元が異なる物のように思います。goto文の場合は使用自体を禁止されているケースも多く、どちらかと言うと「拳銃は簡単に人を殺めることが出来てしまうから禁止しよう」という発想の方に近いように思います。
そのためgoto文が頭ごなしに否定されたり、過剰に嫌悪されてしまっている現状があっても致し方ないことなのかもしれません。
余談ですが、このgoto文の境遇はどこか、自由放任なC言語や複雑多岐なC++言語が置かれている現状にも近いものを感じます。
プログラミングの世界には「C言語を使うと自分の足を誤って撃ち抜いてしまうことがある」という有名な言葉がありますが、これはまさにgoto文にも当てはまっているように思います。
goto文は教養
そのような現実があるゆえに今更goto文の有効性を説いたところでどうにもならない気もしてくるのですが、世の中の熟練プログラマの中にはgoto文の危険性を十分に理解した上で、あえてgoto文を有効的に使いこなそうとしている人達も多くいるため、彼らの言い分や境遇を理解するためにも、goto文の有効性と危険性は世のプログラマであれば誰しもが理解していてしかるべき事柄なのではないかとも思うのです。