コンテンツにスキップ

英文维基 | 中文维基 | 日文维基 | 草榴社区

「Goto文」の版間の差分

出典: フリー百科事典『ウィキペディア(Wikipedia)』
削除された内容 追加された内容
編集の要約なし
Cewbot (会話 | 投稿記録)
m Bot作業依頼: sourceタグをsyntaxhighlightタグに置換 (Category:非推奨のsourceタグを使用しているページ) - log
12行目: 12行目:
次のように、'''ラベルの付いた文'''と併用する{{efn|C言語以外のことも考えれば、一般的にはラベルのみあれば良く、文は絶対に必要というわけではない。ラベル単体では存在できず「ラベル付き文」とする必要があるのはC言語の単なる構文上の制限である。}}。
次のように、'''ラベルの付いた文'''と併用する{{efn|C言語以外のことも考えれば、一般的にはラベルのみあれば良く、文は絶対に必要というわけではない。ラベル単体では存在できず「ラベル付き文」とする必要があるのはC言語の単なる構文上の制限である。}}。


<source lang="c">
<syntaxhighlight lang="c">
clear:
clear:
x = 0;
x = 0;
……
……
goto clear;
goto clear;
</syntaxhighlight>
</source>


goto文によって、そこからclearラベルの付いた文にジャンプし、そこから処理を続ける。
goto文によって、そこからclearラベルの付いた文にジャンプし、そこから処理を続ける。

2020年7月5日 (日) 22:41時点における版

プログラミング言語におけるgoto文(ゴートゥぶん、: goto statement)とは、手続き列中の指定された場所(専らラベルで指定される)に無条件にジャンプ(移動)する、という制御構造のひとつである「文 (プログラミング) 」である。古い文献などで "go to" と離していることもあるのは、英語の go to どこそこ、といったような言い回しとの類似のためでもあり、FORTRANではプログラム中の空白は基本的に無視されるので、goto でも go to でも同じだったからという理由もある(BASICにも、どちらも使えるようにしているものもある)。

概要

goto文は、それ単体では働きを持たせることはできず、必ずラベルか何かによって飛び先が必要である。飛び先のほうにcome fromという文を置き、飛ぶ元にラベルを置く、という「comefrom文」という(冗談半分[1]ではあるが)提案もある(提案自体はジョークだが、同等の機能がある言語は実際にいくつかあり、プログラムの理論上の研究対象にもなっている)。機械語における分岐命令の一種である無条件分岐と、アセンブリ言語のラベルをそのまま手続き型プログラミングに持ち込んだものと言え、何らかの条件分岐との組み合わせによって、ループであるとか、コードブロックの飛び越しであるとかいったような機能の一部となることができる。

「以前に実行した場所に戻る」というループ用途なのか、それともこの先にあるコードは別の流れの一部なので「単に飛び越したいだけ」というジャンプ用途なのか、という単純なことすら、goto文ではその見かけからは分からない。if文while文と比較して考えれば、そういった「意図の不明瞭さ」は明白であり、後述のように、if文やwhile文で単純に書けることであれば、gotoは使うべきではない。一方で、深く多重にネストしたループからの脱出など(そもそも、そのようなループ自体に問題があることもあるとは言え)、gotoを使ったほうが単純かつ明確に書ける場合もあり[注釈 1]、特にC言語においてはgotoを教条的・無条件に排除するべきではない。

資源の確保と解放などのために、プログラム片の入口と出口が必ず対応している必要がある、といった場合などは、gotoに限らず、いわゆる「途中return」等の他の多くの技法も制限されるので、以下のgoto文の議論とはきちんと区別すべきであるし、またそういった場合の制限を全てのコーディングに適用するべきではない。

構文

次のように、ラベルの付いた文と併用する[注釈 2]

clear:
    x = 0;
……
goto clear;

goto文によって、そこからclearラベルの付いた文にジャンプし、そこから処理を続ける。

批判

Cなどの構造化プログラミング言語においては、goto文はむやみに使ってはいけないというルールが、プロジェクト等のガイドライン等として定められていることがある。これは、goto文が原始的で自由度の高すぎる機能であるため、安易なgoto文の使用はプログラムの構造化を妨げ、デバッグなどが行いにくくなり、バグの発生や、メンテナンス性・可読性の低下の原因になりやすいからである。

しかし、多重にネストしたfor文if文while文などでエラー処理や例外処理などが複雑になる場合はgoto文を使った方がプログラムがすっきりと書けるケースもあるため、プログラムの構造を熟知したプログラマが状況に応じて使い分けるものとされている。

エラー処理や例外処理RAIIなどの仕組みが充実している言語の場合、goto文が必要になるケースが少ない。この傾向はC言語よりも後発のオブジェクト指向言語で顕著である。そのため、言語仕様として始めから用意されていないケースもある。こうした言語としては、Javaなどが挙げられる[注釈 3]。一方では、PHPで、2009年にリリースされたバージョン5.3からgotoが追加された[2]ように、高度化する言語構造の中でgoto文が一定の再評価を受ける例もある。

BASICの様な言語や低レベルの制御言語ではgoto文は不可欠であり、goto文を利用しないと分岐やループを使ったプログラムが記述出来ないものもある。しかし、拡張されたBASICの中には、goto文がほとんど不必要になってしまっているものもある。

前述のように、goto文の安易な使用はプログラムの可読性を著しく低下させる。こうした可読性の低いコードのことを、制御構造が複雑に絡まっているという意味を込めて、スパゲティコードと呼ぶことがある。

goto文論争

構造化プログラミング」を提唱していたコンピュータ科学者らの一人であったダイクストラは、1968年にGo To Statement Considered Harmful(「Go To 文は有害(Harmful)とみなされる」)という刺激的な記事を国際学会ACMの学会誌Communications of the ACMに投稿し(ただし、本人が付けたタイトルはA Case Against the Goto Statementという穏便なもので、少なくともタイトルの過激さと、レターとして発表を急いだことは、編集を担当していたヴィルトによるものである)、こんにちでは構造化プログラミングに関して最も良くその名前だけが知られている論争となっている(その内実は言葉の有名さの割には全く知られていないし、そもそも内容や意味の理解は半世紀という時代の違いによって、かなり難しくなっていることも確かである)。クヌースの言葉を借りるならば、「go to 文除去の話の二番目の場面は,多くの人たちが第一幕だと思っている事実である.」[3](という解説自体も[注釈 4]1974年に書かれたものである)。

また considered harmful というフレーズはその後、定番ネタとして、しばしば似たような深刻な、あるいは軽妙な論争に関して付けられるものとなっている(英語版en:Considered harmfulの記事などを参照)。

ダイクストラの主張

“Go To Statement Considered Harmful”[4]の趣旨は次の通りである。

  • 人間が時間によって変化するプロセスを把握する能力は、プログラムの静的な関係を把握する能力に比べて劣っているため、静的なプログラムテキストの構造と時間によって変化するプロセスの構造をなるべく近づけるのが重要である。
  • そのためにはプロセスの進捗を表す簡潔な指標が必要である。指標とは例えば実行中の行番号・その時点でのスタックトレース・行番号とループを回った回数のペアなどである。
  • 例えば、1人が部屋に入るごとにカウンタを増やしていくプログラムにおいて、カウンタが室内の人数-1である瞬間はどこにあるのかという問いに答える際に、簡潔な指標があればすぐ答えられるが、簡潔な指標がなければ正確な答えは難しくなる。
  • goto文を無条件に許してしまうと簡潔な指標は得られなくなってしまうため、高水準プログラミング言語においてはgoto文は廃止するべきである。

その一方でクヌースの指摘[5]によると、ダイクストラは“Structured Programming”[6]においてはgoto文には触れていない。実際に“Structured Programming”においては“sequencing should be controlled by alternative, condtional and repetitive clauses and procedure calls, rather than by statements transferring control to labelled points.”との1文があるのみでそれ以外では触れていない。

また、「3つの基本構造」(後述)についても、“Go To Statement Considered Harmful”においては“I do not claim that the clauses mentioned (引用者註: 順次・分岐・手続き呼び出し・反復) are exhaustive in the sense that they will satisfy all needs”とし、「3つの基本構造」には固執していない。

「構造化プログラミングの観点からgoto文を使うのは望ましくない」ものの「単にgoto文を使わなければ見通しが良くなる」という考えは“Go To Statement Considered Harmful”[4]でも否定されており、goto文の有無のみに固執するのは不毛である。構造化プログラミングの本質の一つは、状態遷移の適切な表現方法とタイミングを見極めることである[7]

3つの基本構造

「goto文有害説」は、ほとんどの場合、「構造化定理」(en:Structured program theorem)に結びつけて主張されたものだと誤解にもとづいて間違って信じられている。構造化定理は、

  • 連接 (sequence): 文1; 文2
  • 選択 (selection): if 式 then 文1 else 文2 fi
  • 繰返し (iteration): do 文 od

という、「3つの基本構造」によって、フローチャートで記述された計算可能な関数は、全て表現できる、というものである。この定理の意味する所は、チャーチ=チューリングのテーゼと同じようなものである。すなわち、計算可能な関数について、それを計算するチューリングマシンを構成することもできるし、ラムダ計算によって計算することもできるし、帰納的関数として定義することもできる、といったことと同様に、フローチャートでも、あるいは「3つの基本構造」の組み合わせによってでも表現できる、ということである。

できる、というだけで、そのようにして表現されたものが人間にわかりやすいか否かについては全く何も主張していないにもかかわらず、「この理論に従えばgotoを除去できる」(これは正しい)、「ゆえにわかりやすいプログラムになる」(これは正しくない)というのが、「goto文有害説」であるとして信じられるようになったため、この記事内を含め、そういったような記述がしばしば見られるが、前提の時点で間違っている。

構造化定理に従って「gotoの無いプログラム」に書き換えたプログラムが実際のところどのようなものであるのかは、英語版記事の en:Structured program theorem#Single-while-loop, folk version of the theorem に示されている。クヌースは「go to 文を用いた構造的プログラミング」の中で、これと同様のプログラムを示し「これですべての goto 文を除去できたわけであるが,実際にはすべての構造を失ってしまっている.」と述べ、構造化定理が示すことは、全くの「構造化プログラミング」であることを警告した。

goto擁護派

一方、goto文を使わずに3つの基本構造による代替を行うと、理論上は同値であっても実際にはプログラムの実行速度や記憶容量の点で性能が劣化する場合があることを示し、goto文を擁護する意見もあった[8]

前の節で述べたように、本来の主張では、goto文は全て3つの基本構造による代替によって書けるのだから、それにより書き換えよう、などという主張ではなかったので、「理論上は同値であっても実際にはプログラムの実行速度や記憶容量の点で性能が劣化する場合があることを示し、goto文を擁護する意見」というものが、そもそも変である。

ACMの年次大会(1972)の討論会では、トップダウンでプログラムを分割するよりgoto文を使う方が適した事例があり、証明には関心がないという意見(William Wait)や、goto文を残せば選択の余地があるが、無くしてしまうと必要になったとき困るだろうという意見(Guy Steel)などが出された[9]

条件文とgoto文を正しく使うことで、FORTRANでもALGOLの基本機能を実現できることを例に挙げ、プログラマは必要な機能がプログラミング言語で直接表現できないとき、どのように実装するか工夫できるべきであるという主張もあった(S.W.スリア)[10]

また、ドナルド・クヌースは「go to 文を用いた構造的プログラミング」(『文芸的プログラミング』収録)の中で、いくつかのgotoを使ったほうが良いだろうという例を挙げているが、その中には、再帰呼出しのある正当なプログラムを、正当な変形によってループによるプログラムに書き換えた結果「ループの中に飛び込むgoto」になる、といったような例も挙げている[5][注釈 5]

gotoの現在

現在C言語を除く主流派の言語では、そのままのgoto文はほとんど見られなくなった。替わりにbreak文continue文、もしくは例外処理のような特殊脱出(去勢されたgotoとも呼ばれる(実際には関数呼出しをまたいだ、いわゆる大域脱出もできるのだから、gotoよりも例外処理のほうが強力である(が、それを理解できない者も多い)))をサポートし、単純な制御構造だけでは弱いと考えられる部分を補っている。さらにクロージャコードブロック継続のような強力な制御機構を使い、抽象度の低いgoto文を使う必要性を低くした言語もある。例えばHaskellにおいてはモナドを利用して例外や非決定性計算などの様々な制御構造を表現できる。またSmalltalkIoにおいても制御構造はブロックを扱うメソッドとして表現している。Scheme等でサポートされている継続は「引数付きgoto」と呼ばれることもある。

一方で、例えば1999年から設計されたD言語はgoto文を含んでいる[11]PHPにも2009年にリリースされた5.3において制限された形ではあるがgoto文が追加された[12]

その他の話題

それまでの職人芸的なプログラミングの時代から、構造化プログラミングというパラダイムの提唱によって、プログラミング技法の体系化を試みるプログラミング工学という学問が芽生えたと言っても過言では無いだろう[要検証]

なお、論文“Go To Statement Considered Harmful”は、その半ば挑戦的な題名がプログラミング以外の様々な分野に及んで評判となり、それをもじった様々な “~ Considered Harmful”といった論説やジョークが生まれたen:Considered harmful 。極めつきは、何かが有害であることだけが強調される題名の有害性を指摘した“‘Considered Harmful’ Essays Considered Harmful”であろう。同じくWhat led to "Notes on Structured Programming" においてダイクストラは、Millsによって矮小化されたgoto文廃止という概念のもと、IBMが用語としての「構造化プログラミング」を盗用したと語っている。

ダイクストラの著書は、分かりにくいことと誤解を招きやすいことで定評がある[13][14][15]。それを憂いたディビット・グリース英語版マダガスカル語版ロシア語版は、ダイクストラ流のプログラミングについて体系化した書籍「プログラミングの科学」(The Science of Programming)を書いた[14]

gotoとバグ

gotoを使用しなかったことによる大規模障害

1990年1月15日に起きた、AT&Tの長距離電話網の停止 (crash) は、break文による脱出先の勘違いによるものであった。en:List of software bugs#Telecommunicationsも参照。

そもそもソフトウェアの制御パステストを十分に実施していなかったせいで不具合が発見されなかったことが障害につながったのだが[16]、適切な名前のラベルを用意し、ループ脱出にgotoを使っていれば避けられたバグでもあった。

gotoを使用したことによる脆弱性

アップルのSSL/TLS実装で発見された脆弱性CVE-2014-1266には、goto failという通称がある。goto文の誤った記述により、本来必要な署名検証処理が実行されずに処理成功として扱ってしまうというものであった。

ただし、このバグを正確に表現すると以下のような原因の複合であり、gotoは「たまたまそこにあった文がgotoだった」と捉えるのが普通のプログラマの感覚である。すなわち、

  1. if文の帰結節に、ブロック(「複文」)だけでなく、「式文」などの単なる「文」も書ける、というALGOLやC言語の構文
  2. そのために、インデントによる見た目と、真の構造が一致していない、というミスリード状態に気が付きにくいこと
  3. そのために、1個目のgoto文により、一見では到達不能コードに見える2個目のgoto文が、到達可能だったこと
  4. そのために別の、セキュリティ的に絶対に実行されなければならないコードが、到達不能コードになっていたこと
  5. 2個目のgoto文は、到達不能コードだと思うのならば、放置せずに削除しなければならなかったこと
  6. 一方で、2個目のgoto文は実際には到達不能コードではなかったので、第三者には、その部分を見ただけでは、削除して良いのか判断不可能だったこと

脚注

注釈

  1. ^ Java(gotoが使えない言語)のラベル付きbreakなどは、そのような場合においてgoto無しでも簡潔に書けるようにするためにある。
  2. ^ C言語以外のことも考えれば、一般的にはラベルのみあれば良く、文は絶対に必要というわけではない。ラベル単体では存在できず「ラベル付き文」とする必要があるのはC言語の単なる構文上の制限である。
  3. ^ Javaの場合、gotoを不要とするために充実しているのは、ラベル付きbreakとcontinueであり、例外処理機構はgotoよりも大きなスコープでのジャンプ(C言語で言えばgotoではなく、setjmp/longjmpに相当)である。
  4. ^ (訳ではなく、原文は)
  5. ^ 「ループの中に飛び込むgoto」というのは、一般には「最も許されないタイプのgoto」と考えられている[要出典]ものであり、しばしば見られる、クヌースの「go to 文を用いた構造的プログラミング」を紹介して「例えば、エラー処理のように、goto文を使う方が分かりやすい場合があり、その場合、goto文を使ってもよい」といったように纏めている解説は(たとえば http://monoist.atmarkit.co.jp/mn/articles/1008/17/news092.html )その解説者が全く論旨を読めていない可能性があるので注意したい。

出典

  1. ^ ha ha only serious
  2. ^ PHP: 新機能 - Manual - PHPマニュアル(2013年12月4日閲覧)
  3. ^ 有澤誠訳『文芸的プログラミング』 p. 45
  4. ^ a b E. Dijkstra (1968). “Go To Statement Considered Harmful”. Communications of the ACM 11 (3): 147-148. CiteSeerx10.1.1.132.875. 
  5. ^ a b Knuth, D. E. (1974). “Structured Programming with go to Statements Computing Surveys”. ACM, New York, NY, USA 6 (4): 261-301. CiteSeerx10.1.1.103.6084. 
  6. ^ E. W. Dijkstra, “Structured Programming”, In Software Engineering Techniques, B. Randell and J.N. Buxton, (Eds.), NATO Scientific Affairs Division, Brussels, Belgium, 1970, pp. 84–88.
  7. ^ E.W.ダイクストラ、W.H.J.フェイエン、玉井浩(訳)、1991、『ダイクストラ「プログラミングの方法」~ 論理学を用いた正しいプログラムの作り方 ~』、サイエンス社 ISBN 4781906311
  8. ^ Frank Rubin, "GOTO Considered Harmful" Considered Harmful, Communications of the ACM, Vol.30, Issue 3, 1987, pp.195-196.
  9. ^ B.リーヴェンワス編, ed. (1975), “GO TO 論争:第2部 GO TO 論争”, bit (共立出版) 7 (5): 10-26 
  10. ^ 金山裕 編, "構造的プログラミング −批判と支持−", bit, Vol.7, Issue 7, 1975, pp.6-13, 共立出版.
  11. ^ Language Reference Goto Statement
  12. ^ PHP マニュアル goto
  13. ^ 木村泉, "GO TO 論争:第3部 解説", bit, Vol.7, Issue 5, 1975, pp.27-39, 共立出版.
  14. ^ a b 二木厚吉 監修, ソフトウェアクリーンルーム手法, 日科技連, 1997.
  15. ^ 木村泉, "ダイクストラ教授とふた付き命令", bit, Vol.8, Issue 9, 1976, pp.29-34, 共立出版.
  16. ^ All Circuits are Busy Now: The 1990 AT&T Long Distance Network Collapse

関連項目

外部リンク