1. ホーム
  2. language-agnostic

[解決済み】GOTOはまだ有害と考えられている?[クローズド]

2022-03-29 02:01:21

質問

誰もが知っているDijkstraの 編集者への手紙:有害と思われる声明に行く (また こちら .htmlのトランスクリプトと こちら .pdf)以来、可能な限りgoto文を排除しようとする動きが強まっています。gotoを使えば、メンテナンス不能な無秩序なコードを作成することは可能ですが、それでもgotoは 現代のプログラミング言語 . 高度な 継続 Schemeの制御構造は、洗練されたgotoと表現できる。

どのような状況でgotoを使用する必要があるのでしょうか?避けるべきはどんな場合か?

フォローアップの質問として。C には setjmp() と longjmp() という関数があり、現在のスタックフレーム内だけでなく、 呼び出しフレーム内のどのフレームでも goto できる機能を提供します。これらはgotoと同様に危険とみなされるべきでしょうか?もっと危険でしょうか?


ダイクストラ自身は、その肩書きを後悔していた。の末尾に EWD1308 (また こちら .pdf)と書いています。

最後に記録として短い話をします。 1968年、Communications of the ACMは というタイトルで私の文章が掲載されました。 というタイトルです。 を考慮したgoto文。 有害 後年、この言葉が使われるようになる。 最も頻繁に参照される。 しかし、残念なことに、しばしば作者によって のみで、それ以上のものを見たことがなかった。 の礎となったタイトルです。 私の名声は、テンプレート化されました。 の下で様々な記事を目にすることになります。 Xは有害であると考えられています。 というタイトルのものを含め、ほとんどすべてのX ダイクストラは有害だと考えている。しかし 何が起こったのか?私が投稿した というタイトルで論文を発表しました。 反対意見 gotoステートメント というのは 出版を早めるために 編集者が「quot;手紙」に書き換えたのです。 その過程で、彼は、"The Editor" "と名付けた。 新しいタイトルが付けられました。 発明 編集者は、ニクラウス ヴィルト

このテーマについて、Dijkstraの論文に匹敵するような、よく考えられた古典的な論文は次のとおりです。 go toステートメントを用いた構造化プログラミング ドナルド・E・クヌース著)。両方を読むと、文脈と独断的でない理解を再確立するのに役立ちます。この論文では、この件に関するDijkstraの意見が報告されており、さらに強力である。

<ブロッククオート

ドナルド・E・クヌース 私は、このような提示をすることで を見ることは、実は反対ではないのです。 ダイクストラの考えと大きく異なります。 彼は最近、次のように書いています。 という罠にはまらないでください。 私がひどく について独断的である。 ステートメント]があります。 私は 他の人が作っているような気がする まるで宗教のように プログラミングの概念的な問題 一つのコツで、解決できるかもしれない。 シンプルなコーディングの規律 "です。

解決方法は?

以下の記述は一般論です。例外を主張することは常に可能ですが、通常は(私の経験と謙虚な意見では)そのリスクに見合うものではありません。

  1. メモリアドレスの無制限な使用(GOTOまたは生ポインタ)は、簡単に回避できるミスを犯す機会が多すぎます。
  2. コード内の特定の場所に到達する方法が多ければ多いほど、その時点のシステムの状態について確信が持てなくなります。(下記参照)
  3. 構造化プログラミングとは、GOTOを避けることよりも、コードの構造をデータの構造に一致させることだと思います。例えば、繰り返されるデータ構造(配列、シーケンシャルファイルなど)は、当然ながら繰り返されるコード単位で処理されます。組み込みの構造体(while, for, until, for-eachなど)を持つことで、プログラマは同じ決まりきったコードパターンを繰り返す退屈さを回避することができるのです。
  4. GOTOが低レベルの実装の詳細であっても(必ずしもそうとは限りません!)、プログラマが考えるべきレベルより下のことです。どれだけのプログラマが、生のバイナリで個人的な小切手帳の残高を計算しているでしょうか?データベースエンジンにキーを提供する代わりに、ディスクのどのセクタに特定のレコードがあるかを気にするプログラマがどれだけいるでしょうか(そして、もし私たちのプログラムをすべて物理ディスクのセクタという観点から本当に書いたら、どれだけの方法で物事がうまくいかなくなるでしょうか)。

以上、脚注。

ポイント2について、以下のコードを考えてみましょう。

a = b + 1
/* do something with a */

コード内の「do something"」ポイントでは、高い信頼性を持って次のように述べることができます。 a よりも大きい。 b . (そう、トラップされていない整数のオーバーフローの可能性は無視しています。単純な例でつまづかないようにしましょう)。

一方、もしこのコードがこのように読めたとしたら。

...
goto 10
...
a = b + 1
10: /* do something with a */
...
goto 10
...

ラベル10に到達する方法が多種多様であるため、ラベル10とラベル10の関係を確信するためには、より一層努力しなければならない。 ab その時点で (実際、一般的なケースでは決定不可能です!)

4について、「コードの中のどこかに行く」という概念は単なるメタファーです。CPUの内部では、電子と光子(廃熱のため)以外、実際には何も行っていないのです。私たちは、より有用な別の比喩を得るために、ある比喩をあきらめることがあります。数十年前、次のような言語に出会ったことがあります。

if (some condition) {
  action-1
} else {
  action-2
}

は、action-1 と action-2 をアウトオブラインのパラメータレスルーチンとしてコンパイルし、条件のブール値を使ってどちらかを起動する2引数の VM オペコードを1つ使って、仮想マシン上に実装されました。コンセプトは、「ここかあそこか」ではなく、「今呼び出すものを選択する」という単純なものです。これも比喩の変更です。