見出し画像

GOTO論争の記憶

その昔、プログラミングの「構造化」が叫ばれた時代に GOTO という命令が叩かれまくったことがありました。GOTO という命令は古のプログラミング言語にはだいたいあって、プログラムの実行する場所を指定した行に無条件で移動させる命令です。そもそもCPUのマシン語では、次の命令を取り出すアドレスを無条件に変更するジャンプ命令か、条件付きで変更する ブランチ命令しかありません。ですから、これに対応する GOTO命令かIF命令があったに過ぎません。

これの何がイケなかったと言えば、どこからでも自由な場所に行けてしまうことです。ループの真ん中から脱出したり、いきなりループの途中に飛び込むことはもちろん、BASICではサブルーチンの途中に GOTO することも可能です。古のプログラミング言語では、制御構造と言えば、IF 以外には回数を指定して繰り返すDO やFORといったループくらいしかなく、そもそもフローチャートを描けば、そこにはループすら定義されておらず GOTO で処理を移すのが当たり前でした。

goto文

モダンなプログラミング言語では、豊富な制御構文を備えているので、普通は GOTO 何か使わなくても大抵の条件分岐を書くことができます。また例外機能を持っていればエラー処理も GOTO 無しでまとめられます。C言語のように例外が使えないと、ついつい goto を使ってしまうこともあります。他にも多重ループからの脱出の際に簡潔に掛けることから goto を使うこともあったりしますね。

ちなみに多少の制限はありますが、Java でも goto に近いものはありますし、python に goto はありませんが、何と goto というモジュールが作られていたりします。

Java のジャンプ演算子

多重ループを一気に抜ける

まあ、この程度であれば FORTRANやBASIC と比べれば可愛いものです。FORTRANには行番号変数というものがあって変数に整数を代入すれば、その値に飛べるというとんでもない書き方が出来ますし、BASICにも計算型GOTOというのがあって式の結果で得られる行番号に飛ぶことが出来ますからね。ON GOTO なら、まだわかりやすいくらいです。BASICもモダンなVBになると、こういった構文は無くなりましたが、ループには種類があるので、これを悪用して FOR と DO で二重ループを作れば、EXIT FOR と EXIT DO で抜けるループを変えることが出来るので、これを乱用した記憶もあります。

C言語の場合、goto で飛べるのは関数の中だけですから、どうしても必要性があれば使ってしまっても構わないのですが、処理系によっては「レジスタ変数の値は保存されない」という恐ろしい注釈が書いてあったり、そもそも最適化が行われなくなったりすることもあるので、ちょっと勇気がいります。これがC++になると互換性のためにちゃんと使えるのですが(少しだけ制限が追加されています)、goto で制御を移すとスコープの関係でコンストラクタやデストラクタが呼び出されないことがあるという恐ろしい副作用があるので、使える場所は限定されます。

C言語でgoto文を適切に使うとメリットがあります

ちなみにC言語にはもっと強力な関数も用意されていて、これを使うと関数の壁を超えてどんな場所へも飛ぶことが出来ます。

setjmp(3)

これは複雑な構造を持つライブラリなどで有用で、異常が発生し処理が継続できない場合に例外のように特定の関数に戻ることが出来るので、例外を持たない言語では重宝します。実はこの関数の実装を見ると、CPUのすべてのレジスタを保存しておいて、戻りたい時に保存した内容をレジスタに戻すというもので、プログラミングカウンタもスタックポインタも戻してしまうので、どこからでも元に戻せるというものです。確かに確実ですがちょっと恐ろしさも感じますよね(当然レジスタ変数は吹っ飛びます)。

考えてみれば signal 処理も goto の一種には違いなく、エラー状態となってしまった場合には、もう細かな処理を続けても仕方がないので、そういった意味では goto のような処理は不滅なのかもしれません。この手の処理は業務向けのコードなどでは絶対に落ちてはいけないので(落ちるときにも適切な手順がある)、なかなか腕の見せどころでもあるんですよね。

ヘッダ画像は、AIに描いて貰いました。

#プログラミング言語 #GOTO #構造化 #行番号 #多重ループ #setjmp #大域脱出

いいなと思ったら応援しよう!

kzn
頂いたチップは記事を書くための資料を揃えるために使わせていただきます!