goto文




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




目次






  • 1 概要


  • 2 構文


  • 3 批判


    • 3.1 goto文論争


    • 3.2 ダイクストラの主張


    • 3.3 3つの基本構造


    • 3.4 goto擁護派


    • 3.5 gotoの現在


    • 3.6 その他の話題




  • 4 gotoとバグ


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


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




  • 5 注釈


  • 6 脚注


  • 7 関連項目


  • 8 外部リンク





概要


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


「以前に実行した場所に戻る」というループ用途なのか、それともこの先にあるコードは別の流れの一部なので「単に飛び越したいだけ」というジャンプ用途なのか、という単純なことすら、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においてはモナドを利用して例外や非決定性計算などの様々な制御構造を表現できる。またSmalltalkやIoにおいても制御構造はブロックを扱うメソッドとして表現している。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. ^ abE. Dijkstra (1968). “Go To Statement Considered Harmful”. Communications of the ACM 11 (3): 147-148. .mw-parser-output cite.citation{font-style:inherit}.mw-parser-output .citation q{quotes:"""""""'""'"}.mw-parser-output .citation .cs1-lock-free a{background:url("//upload.wikimedia.org/wikipedia/commons/thumb/6/65/Lock-green.svg/9px-Lock-green.svg.png")no-repeat;background-position:right .1em center}.mw-parser-output .citation .cs1-lock-limited a,.mw-parser-output .citation .cs1-lock-registration a{background:url("//upload.wikimedia.org/wikipedia/commons/thumb/d/d6/Lock-gray-alt-2.svg/9px-Lock-gray-alt-2.svg.png")no-repeat;background-position:right .1em center}.mw-parser-output .citation .cs1-lock-subscription a{background:url("//upload.wikimedia.org/wikipedia/commons/thumb/a/aa/Lock-red-alt-2.svg/9px-Lock-red-alt-2.svg.png")no-repeat;background-position:right .1em center}.mw-parser-output .cs1-subscription,.mw-parser-output .cs1-registration{color:#555}.mw-parser-output .cs1-subscription span,.mw-parser-output .cs1-registration span{border-bottom:1px dotted;cursor:help}.mw-parser-output .cs1-ws-icon a{background:url("//upload.wikimedia.org/wikipedia/commons/thumb/4/4c/Wikisource-logo.svg/12px-Wikisource-logo.svg.png")no-repeat;background-position:right .1em center}.mw-parser-output code.cs1-code{color:inherit;background:inherit;border:inherit;padding:inherit}.mw-parser-output .cs1-hidden-error{display:none;font-size:100%}.mw-parser-output .cs1-visible-error{font-size:100%}.mw-parser-output .cs1-maint{display:none;color:#33aa33;margin-left:0.3em}.mw-parser-output .cs1-subscription,.mw-parser-output .cs1-registration,.mw-parser-output .cs1-format{font-size:95%}.mw-parser-output .cs1-kern-left,.mw-parser-output .cs1-kern-wl-left{padding-left:0.2em}.mw-parser-output .cs1-kern-right,.mw-parser-output .cs1-kern-wl-right{padding-right:0.2em}
    CiteSeerx: 10.1.1.132.875.
     


  5. ^ abKnuth, D. E. (1974). “Structured Programming with go to Statements Computing Surveys”. ACM, New York, NY, USA 6 (4): 261-301.
    CiteSeerx: 10.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. ^ ab二木厚吉 監修, ソフトウェアクリーンルーム手法, 日科技連, 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




関連項目



  • if文

  • for文

  • while文

  • 継続

  • 非構造化プログラミング

  • 制御構造



外部リンク



  • Go To Statement Considered Harmful について


    • Go To Statement Considered Harmful Edsger W. Dijkstra


    • Go To Statement Considered Harmful: A Retrospective David R. Tribble


    • Code Reads #2: Dijkstra's "Go To Statement Considered Harmful" Scott Rosenberg

    • Radium Software Development - Go To Statement Considered Harmful


    • What led to "Notes on Structured Programming" (EWD1308) Edsger W. Dijkstra









Popular posts from this blog

Identifying “long and narrow” polygons in with PostGISlength and width of polygonWhy postgis st_overlaps reports Qgis' “avoid intersections” generated polygon as overlapping with others?Adjusting polygons to boundary and filling holesDrawing polygons with fixed area?How to remove spikes in Polygons with PostGISDeleting sliver polygons after difference operation in QGIS?Snapping boundaries in PostGISSplit polygon into parts adding attributes based on underlying polygon in QGISSplitting overlap between polygons and assign to nearest polygon using PostGIS?Expanding polygons and clipping at midpoint?Removing Intersection of Buffers in Same Layers

Masuk log Menu navigasi

อาณาจักร (ชีววิทยา) ดูเพิ่ม อ้างอิง รายการเลือกการนำทาง10.1086/39456810.5962/bhl.title.447410.1126/science.163.3863.150576276010.1007/BF01796092408502"Phylogenetic structure of the prokaryotic domain: the primary kingdoms"10.1073/pnas.74.11.5088432104270744"Towards a natural system of organisms: proposal for the domains Archaea, Bacteria, and Eucarya"1990PNAS...87.4576W10.1073/pnas.87.12.4576541592112744PubMedJump the queueexpand by handPubMedJump the queueexpand by handPubMedJump the queueexpand by hand"A revised six-kingdom system of life"10.1111/j.1469-185X.1998.tb00030.x9809012"Only six kingdoms of life"10.1098/rspb.2004.2705169172415306349"Kingdoms Protozoa and Chromista and the eozoan root of the eukaryotic tree"10.1098/rsbl.2009.0948288006020031978เพิ่มข้อมูล