ニコニコ大百科モバイル

7/2(月)よりスマホまたはPCでアクセスした場合、各デバイス向けのサイトへ自動で転送致します


goto


ヨミ: ゴートゥ
掲示板をミル!
26カキコ!

gotoとはプログラミング言語の構文のひとつであり、その使用を巡って論争が絶えないことで有名である。


概要


古典的にはgotoは条件ジャンプを行うための構文であり、その名の通り「あそこの(あのラベルの)処理に飛べ!」という単純明解な機である。 C言語のgotoを基準にすると、同一関数内である限り、ラベルが書ければどこにでもジャンプすることが出来、ジャンプ先から処理を継続する。ジャンプ元には特にgotoなどで定されない限り戻ってこない

gotoをサポートする言にはFORTRAN, BASIC, C (当然C++も)と、メジャー古参高級言が名を連ねており、いかにも「由緒正しきスタンダードな機です」感が漂うが、現在では実行速度を重視する分野などを除けば、条件ジャンプができるgotoは好ましくない機とする意見が流を占めている。

なお、GoD言語は"goto"を採用しているが、表記こそ"goto"であるものの、後述のように用途制限により実質的には"古典的gotoの代替"となっており、古典的gotoの議論とは関係である。

以降では、古典的gotoに関する議論を中心に取り上げる。


なぜ批判されるか


gotoは関数呼び出しと違って呼び出した場所に戻って来る保がないので、プログラムの構造をぶっちぎって構造化プログラミングを台しにすることが出来てしまう。 ある意味構造化プログラミング敵ともいえる。

状況によっては特定の処理を飛ばす事も容易に行えてしまう。 たとえば、「ファイルを開き、データ読み込み、ファイルを閉じる」という処理があった時、「データ読み込む」処理にgotoが入っていて、gotoで飛んだ先から「ファイルを閉じる」処理に戻ってくるように書くのを忘れてしまうと、ファイルが開いたままになってしまう。

また、安易なgotoの濫用は絡まり合うような処理の流れを生み、本人ですら処理の流れを把握することが困難なソースコードを作り出す。 絡まり合っていることからスパゲティコードと呼ばれる。


歴史



gotoの誕生


gotoの誕生は最古の高級プログラミング言語FORTRANの登場(1957年)にまで遡る。現代のFortran仕様訂を経て現役のプログラミング言語として一部の分野では活躍を続けているが、最初期のFORTRANサブルーチンすらなく(ただし、1958年FORTRAN IIではサブルーチンと関数定義がサポートされている)フロー制御にgotoは必須であった。

もっとも、当時はプログラミング言語といえば機械語アセンブラしかなく、メモリソースコードの長さすら切り詰めねばならないほど少なく、できることも限られていたため、プログラムに構造をもたせる余裕も必要もなかったと言える。


gotoへの批判の誕生


その後、ハードウェア進化と共にプログラムも複雑さを増していくつれて、前述のようなgotoの弊立つようになり、ついには最短経路問題で有名なダイクストラらの1968年の論文「Go To Statement Considered Harmful (Go To構文は有だと考えられる)」で批判されるまでになった。

なおC言語の誕生が1972年であり、上記論文はそれより


goto擁護論の誕生により論争時代へ


gotoのある言語におけるgotoの擁護

構造化定理により、gotoを用いた処理を反復・分岐などの組み合わせに書き換えることは理論上可であるが、その書き換えを行うことで性可読性について不利になるケースもある。

後述のようにC言語では例外処理がないために、goto構文に頼らざるを得ない局面が存在する。

また、gotoのある言の多くは多重ループからの脱出する方法がgotoに頼らざるを得ない(gotoがあるから、多重ループ脱出のための仕組みがいらなかったとも言える)言仕様になっている。


その後


gotoのある先発言語

C言語仕様訂でもgotoの性質は変化しなかったが、多くのプロジェクトコーディング規約などでgotoの使用方法を制限するようになった。

C++はCとの互換性の関係からgotoが存在するが、例外処理機構を持っている(実装されたのは1990年よりも後の話だが)ため例外処理のためにgotoを使う局面はない。

後発言語

Javaを始めとするC言語より後のプログラミング言語の多くは、後述のように"古典的gotoの代替"を用意することで、条件ジャンプとしてのgotoの採用は見合わせている。

余談だが、JavaC言語の反からgoto文を採用していないが、万が一後世でgotoの必要性が立された時のためにgotoを予約としてキープしている。goto議論の呪縛は根深い。


論争の本質


「gotoがないよりはあったほうがプログラムを書くときに便利だが、弊が生じやすい」という点ではおそらく全員意見が一致している。

賛否が別れるのは、一つの問題点を、優先するものの違う2つの立場から捉えているからに過ぎない。すなわち、

という立場である。

もっとも、近年のプログラミング言語の傾向としては(優秀なプログラマーからそうでない者まで)大人数で安全な開発を行えるようにすることを重視するという考えが流なので、今時の言古典的意味でのgotoを採用することはまずない。


議論がかみ合わない点


概要で述べたように、gotoはどこにでも飛ぶことが出来る一方で戻ってくることが保されないために、注意しないと構造化プログラミングを破壊してしまうことが問題なのである。

逆にいうと、goto使用もプログラムの構造を破壊しない限りにおいては構造化プログラミング上の問題を生じない。gotoを使うことが「必ず」問題を引き起こすというわけではないのである。gotoの文字列をにした途端に思考停止してアンチパターンだと糾弾するのはいいことではない。

一方で、gotoを否定する議論では、goto使用による弊という「結果」のみを問題にしているわけではない。「gotoが存在すること」によって弊のある使い方が「出来てしまう」こと自体が問題視されているのである。従って、弊を起こさないように上手に使いさえすればよいというgoto肯定の反論も的を射ていない。可能性を生み出しただけでアウトなんだよ

また、gotoを適切に用いれば構造化プログラミング上は問題ないといっても、コード中にgotoが存在するだけで、そのgotoの適切性を検証しなければならないという管理上の問題が生じる。この場合、gotoを利用している単位での品質管理が重要で、継続してテストコードが書かれ検証されるようにすることであらかじめ問題を検知しておきたい。

そのような環境が整わないのであれば、やはり、gotoが使用可な言であっても使用しないほうがよいだろう。例外があるとしたら、コメントなどで適切性を簡潔に明できる場合や、達人が自分一人プログラミングする場合くらいであると思われる。


古典的gotoの代替


上記のようにgotoでジャンプすることは絶対悪ではなく、構造化プログラミングを妨げないことが保されるならジャンプも有益でありえると言える。

この点に対して、C言語より後の較的新しいプログラミング言語の多くは条件ジャンプとしてのgotoではなく、より限定された範囲でのジャンプ制御命(break, continue, 例外処理, etc.)を代替として提供していることが多い。そういった言では条件ジャンプとしてのgotoが必要になるケースはほぼない。


例外処理(try-catch-finally)


(tryで始まるブロックの中で)規定通りの動作ができないときに例外(Exception)を発生(throwする)させる。例外が発生すると、(tryブロックの直後にある)例外を捕捉(catch)する節までジャンプする。

例外処理は同一関数内という制限を受けずスタックを遡上して関数外に出ること(大域脱出)が可という意味ではC言語のgotoよりも強な機である。その一方で、ジャンプ先はcatch節だけという限定を受けている上、「ファイルを閉じる」のような処理まではスキップしてしまわないように(catch節の直後にある)finally節で実行されることが保されており、構造化プログラミングを破壊しないための安全機構が設けられている。

C++にはfinallyがないが、デストラクタなどを用いて実行の保が可である。


break, continue


for文から抜け出すbreak, continueジャンプの一種であり、古典的gotoの代替と考えることもできる。ジャンプ先はループの末尾に限定されている。C言語でもサポートされているため、これらがないがためにgotoが必要になるケースは少ない。

初期のFORTRANループの脱出にgotoを用いていたが、Fortran 90ではbreak, continueに相当する機サポートされた。

もっとも多重ループからの脱出には、Fortran 90でも、C言語でも、C++でも、gotoに頼るのが定石の一つとして認められている(なお例外処理があれば、gotoを使わずとも多重ループからの脱出は可能な気がする)。

Java以降の言ではbreak, continueラベルを使えるものが多いため、gotoがなくとも多重ループからの脱出は可である。


C言語における"制限された"goto


C言語のように例外処理がない言ではgoto文を用いずに高い可読性を実現出来ないことがあり、goto文を使用すべきとしているプロジェクトも存在する。

しかし、後述の事例に記したように、基本的には上記で述べた例外処理と同等のフローを実現するために使用されている場合がほとんどである(歴史的に考えれば、このエラー処理フローを言レベルサポートしたものが先述の例外処理であると言った方が適切かもしれない)。これらの場合、言仕様上は制限されていなくても、コーディング規約としてgotoのジャンプ先に実質的制限が加えられていると見ることもできる。


制限の強まった"goto"


先述のように、新しい言でも"goto"を採用している言はある。 これらの言のgotoは較的C言語に近い機を有しているが、使用するための制約を強くしたり条件で処理をスキップしないようにするなど、C言語よりも自由度や機を制限したものとなっている。

D

D言語のgotoはC言語と同様に同じ関数の内部のラベルしか参照出来ないようになっている。 それに加えてgotoによって変数の初期化をスキップするようなジャンプは禁止され、またジャンプする場合であってもfinally節の実行は回避されないようになっている。

Go

Goでもgoto構文は採用されており、やはりC言語と同様に同じ関数の内部のラベルしか参照出来ない。 加えてgotoする時点でスコープに入っていない変数ジャンプ先ではスコープに入っているような(i.e. 初期化をスキップする)ジャンプは禁止され、またより内側のブロックへのジャンプも出来ない仕様となっている。


GOTO 関連動画



■sm486838[ニコ動]


GOTO 関連項目



参考: goto使用に関するC言語の事例


C言語によるオープンソースプロジェクトでは、適した場所(例外処理など)に限るという前提ではあるがgotoを利用しているプロジェクトは非常に多い。

gotoが適すると思われるような例であってもgotoを利用しないという場合もなくはないです。


最終更新日: 19/01/11 22:16
タグ検索 パソコン版を見る


[0]TOP
ニコニコ動画モバイル
運営元:ドワンゴ