楽屋裏 - 構造化プログラミング
楽 屋 裏
e-Gadget
2014年09月28日 追記
2017年08月27日 追記
2019年08月21日 追記修正
2017年08月27日 追記
2019年08月21日 追記修正
「CasioBasic入門」シリーズは、改めてキチンと勉強する良い機会になっています。CasioBasic入門12 で、構造化プログラミングについて、チラッと触れたのですが、改めて整理をしてみます。
50年くらい前、COBOL、PL/I、FORTRAN、Pascal などの高級言語が使われるようになって、ソフトウェアの生産性と品質が向上してきました。時期を同じくして、ソフトウェアの需要が増加したため、生産性や品質の向上が追いつかなくなりました。それを「ソフトウェア危機」と呼び、なんとかしなければヤバイという時代がありました(当然私はリアルタイムでは知りませんが、プログラミング雑誌「C Magazine」 などを通して知っていました。
この当時は、アセンブリ言語がプログラミングの主流でした。この言語はプロセッサの動作に近い命令を記述するものなので、ジャンプ命令が非常に多く(gotoの嵐と言っても良い)、プログラムコードからプログラム動作を理解し解析することが簡単ではありません。プログラミングは工芸であり、匠の技の世界でした。作ってみて動かして、不具合が見つかったらそれを直すと言う方法では、生産性や品質の向上は容易に進みません。こういう背景の中、構造化プログラミング(Structured Programming)と言う概念が出てきました。
プログラミングの匠が活躍していた時代に、生産性と品質の向上を目指した新しい考え方「構造化プログラミング」は簡単には受け入れられませんでした。パラダイムシフトの前には必ず旧来の考え方との激しい争いがあるのは、いつの時代でも同じですが、当時も大論争が勃発しました。それでも、世の中はより良いプログラムをより多く必要としていたわけで、それに応えてゆく必要はあり、それが新勢力と旧来勢力の共通目標ではあったのでしょう。ついに両者が歩み寄ることが出来ました。
私が調べる範囲では、その落としどころのきっかけを作ったのが、1974年に発表された Donald Knuth の論文 "Structured programming with goto statement" のようです。この説が最も説得力があり、現実的なように思われます。
ここに落ち着くまえには、2つの重要なポイントがあるとの指摘があります。
1966年にCorrad Boehmら から提案された「構造化定理」
これは、どのようなプログラムでも、下図に示すような、連結(Concatenation)、選択(Selection)、反復(Iteration)の3つで表現できると言う数学理論です(引用)。

要するに、goto がなくてもプログラムを作れると言うことを言っています。それ以上でもそれ以下でもない、単なる数学理論です。この理論が出された時は「構造化定理」とは呼ばれておらず、goto使用禁止を唱える人たちによる命名と言う話もあります。さらに細かいことですが、ここでは「連結」を使っていますが、「順」、「順次」、「順接」と言う和訳も見られます。
1968年にEdsger Dijkstraが書いた書簡"Goto statement considered harmful"
これは、Association of Computing Machinery (ACM) に送られた書簡で、書簡のタイトル「goto文は有害である」通りに、極めてストレートにgoto文の使用禁止を主張するものです。goto文を使うと、プログラムは簡単にスパゲティ構造になり、これには異論の余地はありません。
これが大論争に油をそそいだようです。もうこうなると、どこまで行っても平行線、宗教論争の様相であったに違いないと私は思います。Boehmの構造化定理がいくら数学的に正しくても、それまで goto文を使ってプログラムを作っていたプログラマが、いきなり使うなと言われても、そう簡単に受け入れられるものではないことは想像に難くありません。
ネットで検索すると、今でもgoto論争を見ることができ、そこではダイクストラ (Dijkstra)の名前が必ずでてきます。それくらい根源に迫る劇薬のようなものなのだと思います。
このような歴史的背景があって、10年近くたってから出された Knuth の論文 "Structured programming with goto statement"「goto文を使った構造化プログラミング」は、goto使用是非論争を一旦横に置き、大目標である生産性と品質の向上を達成する構造化プログラミングとは「読んで分かりやすいソースコードを書くこと」であり、非常時には goto もやむなし、と言う大人の議論だと思います。
私の主張: Gotoは用法・用量を守って使いましょう! を支持するものでもあります。
実際問題、2000~3000行の中規模のプログラムを作った経験(個人の趣味で1万行超えの大規模プログラムを作ることは滅多に無いでしょう)では、絶対に必要な時以外に goto文を使うと、あとで絶対に自分の首が絞まります。
私は、エラー処理や例外処理には goto を使っても良いと自分で決めています。この使い方は、goto のジャンプ先が、必ずエラー処理や例外処理になるので、むしろプログラムの流れが明確になる利点があります。
落としどころとして Knuthの論文が受け入れられた歴史的事実を知ることは、考え方に幅を与えるものと思います。今では、構造化プログラミングは空気を吸うくらい当たり前になっているのでしょう。普通にC言語を使えば、自然にこの手法になります。と言うのも、最近の高級言語 (最近のBasic を含む) は構造化プログラミング言語として作られているので当然なわけです。これらには例外処理専用のステートメントが準備されているものがありますが、内部的には goto を使っていて、外から見えないだけだと言えます
生業としてのプログラミング経験の無い私の目には、goto是非論争は子細なことのように映るのです。
Casio Basicは構造化プログラミング風言語
構造化プログラミングは、「読んで分かりやすいプログラムを書こう」という目標で、以下の方針でプログラムを作ることです。
1. 構造化定理に出てくる 1)連結、2)分岐、3)反復 に加えて 4)呼び出し のみで構成されるブロックを作る。
2. このブロックは出口と入り口が1つだけでなければならず、ブロックの連結でプログラムを構成する。
3.Goto はなるべく使わない。使う場合は、先へ進むGoto のみを使い、後戻りするGoto は使わない。
CasioBasicは、これらの感覚でコーディング可能です。
1) 連絡: 要するにプログラムが上から下へ動作する、実はこれは大切なこと
2) 分岐: If文や⇒命令があります。
3) 反復: Doループ、Whileループがあります。
4) 呼び出し: サブルーチンや関数の呼び出し。プログラム呼び出しの Prog コマンドがあり、関数電卓の機能を呼び出す多くの関数がある。
そして、プログラム記法として、処理内容別に「連結」で繋がるブロックを作ることが最も大切です。ブロックとは、複数の処理をまとめて区切り、出口と入り口が1つだけになるようにした機能のかたまりです、。
[2019年08月20日 修正]
構造化プログラミングを行う手続き型言語の要件として、ユーザー定義の関数とローカル変数(局所的変数) がありますが、Casio Basic では仕様上これらが使えません。つまり、サブルーチンに引数を渡したりサブルーチンから戻り値を返せません。また、ローカル変数(局所的変数)が使えず、変数は全てグローバル変数(大域変数)として扱われます。
逆に考えれば、大域変数を利用してサブルーチンとの間での値のやりとりが可能です。そこで、コーディングの工夫で関数のようなサブルーチンを作れます。この手法の一例としては、入力ボックス や 3桁区切り出力 を紹介しています。そこで Casio Basic は構造化Basic ではありませんが、Casio Basic は構造化風プログラミングが可能です。
変数のスコープ(適用範囲) は構造化プログラミングでは重要ですが、それ以上にブロック構造で構成されたコードを上から下へ流れるような制御構造で書くスタイルは、さらに重要だと考えています。現在の "新世代Casio Basic" は、機能別ブロック構造が上から下へ流れる構造をコーディング可能で、このような構造化プログラミングを意識したコーディングは、実際に分かりやすいコーディングに繋がります。現在連載している CasioBasic入門でも、意識的に構造化Basic風プログラミングをしていて、機能別ブロックが連結で繋がるコーディングを体験してもらいながら、処理の変更や追加が楽に行えることを紹介しています。
ちなみに 海外のみで販売されている fx-CP400 や fx-CG500 に搭載されている Casio Basicは、構造化Basicと言えます。定義上は構造化Basic になっていますが、実はこれが極めて使いにくいだけでなく、処理速度がかなり遅いものになっおり、実用プログラムを作って使おうという気にとてもなれないほど中途半端なものです。さらなる進化が望まれます。極めて使い勝手の悪い構造化Basicであり、現在のところ構造化Basicを目指して試行錯誤の段階ではないかと思われます。
実用上は 構造化風プログラミング言語である Casio Basic の方が遙かに使いやすく、処理速度もグラフィックスプログラムを除けば十分速い仕様に、とてもうまくまとまっています。プログラミングが楽しめる言語と言えます。
なお、"新世代 Casio Basic では、使いやすくするために、Basicコマンドを導入する前の 各種ジャンプ命令をそのまま残していますが、それゆえに Goto コマンドの内部動作が複雑になっています。具体的には、多重ループとカウントジャンプの組み合わせで発生する異常動作対策のために Goto 0:Lbl 0 という記述を使います。詳しくは、
ここを参照 ください。
================
ちょっと脱線...
オブジェクト指向プログラミング
構造化プログラミングは30年以上も前に生まれたもので、今ではその問題点がハッキリしていて、それを解決するために考えられた「オブジェクト指向プログラミング」が主流になっています。
プログラムは、手続きとデータから成り立っています。
構造化プログラミングは、プログラムの流れの制御を構造化するもの、つまり手続きを管理するものです。しかし、データについては何も言っていません。プログラムの中の色々な局面で、データに自由にアクセスすると、データの管理が出来なくなります。goto文を野放しにすることで制御構造がグチャグチャになるのと同じことが、データ管理で起きます。これを何とかしよう、と言うのがオブジェクト指向なのです。
私自身は、Visual C++ を使ってきており、最近 C# を使い始め、オブジェクト指向プログラミングの経験だけはありますが、オブジェクト指向プログラミングについて正しくまとめられるかどうか自身がありません。ただその有効性と重要性は肌感覚として認識しているので、少し触れておこうと思います。
プログラムの中から自由にデータアクセスすると、問題が有ったときにプログラム内のどこで誤ったデータ操作をしたのかを見つけるのがかなり面倒になります。そこで、データへのアクセスを大幅に制限してしまおう、と言うのがオブジェクト指向プログラミングの根本にあります。
読み書きできるデータは変数なわけですが、その変数には大域変数(グローバル変数)と局所変数(ローカル変数)があります。大域変数とは、プログラム内のどこからでも自由にアクセスできるので、これが問題になります。
オブジェクト指向プログラミングは、大域変数を無くそうと言うものです。
話を戻して...
CasioBasicはオブジェクト指向ではない
CasioBasicにオブジェクト指向は関係ありません。変数は大域変数のみ、同じ変数に異なるプログラムからアクセスが自由に行える仕様です。CasioBasicには局所変数はありません。
Goto や Lbl で使うラベルの及ぶ範囲は、1つのプログラム内に制限されるのですが、まぁラベルは変数でないし、使えるラベルは英数字1文字に限られるので妥当な仕様です。
使える変数も極めて限られ、A~Z、そして配列変数Z[ ]のみです。頑張って管理するしかありませんし、管理しきれる範囲内と言えましょう。
ですから、CasioBasicを使う場合は、構造化プログラミングを行うのが最良の道と言うわけです。
見方を変えると、30年前の最新技術が、今や単4電池1本で何ヶ月も動作する電卓の中に詰まっているわけで、これは素晴らしいことだと思うのです。
応援クリックをお願いします。励みになるので...