上の反省から、構造化プログラミングでは、サブルーチンにおいて、その中だ け有効なローカル変数というものをとりいれ、この変数は他のルーチ ンからは見られない(ので利用できない)ことから、データの不用意なルーチ ン間の依存関係を無くすようにしました。どういうことかというと (以下はCでの例です)、
#include <stdio.h> int i; // global var. void func() { i = 1; // set global var. } main() { int i; // local var. i = 2; // set local var. printf("%d\n",i); // print the value of "i"(=2) func(); // change gloval but local printf("%d\n",i); // print i = 1 or 2? }上の場合、i は main の中と外のどちらにもありますが、func (Cではサブルー チンを関数の形で定義します)で代入している i は外のもの、main の中で代 入している i は main の中だけで有効な、外のものとは別の i になっている、 というのがポイントです。なので、上のプログラムを実行すると、2を二回出 力します。これでは見通しが非常に悪いので、グローバル変数は出来るだけ (使わなくていいなら)つかわない、という方針でプログラミングが出来るよ うに言語仕様が決まっています。
#include <stdio.h> int func(int i) { i = i*i; // power of i return i; // return the power-ed "i" } main() { int i,j; // local var. i = 2; // set local var. printf("%d\n",i); // print the value of "i"(=2) j = func(i); // CALL func printf("%d %d\n",i,j); // print 2, 4 ("i" is still 2) }上を見てみると、func を呼びだしたときに、その時点での引数の値2が(コピー されて)上の関数 func に渡され、元の i は変更されない、という ことです。このことによっても、サブルーチン間の依存関係を極力へらしてい る、というわけです。
逆に見てみると、高級言語以前では、パラメータを渡すときにはメモリ (のアドレス)を渡す場合が多くありましたが、これは上でいうと i と いう変数を「箱」のまま渡すことになり、そうすると func 内での変 更はそのまま影響を受けるわけです。つまり、2回目の出力が "4 4" になって しまう、ということです。これではデータの流れの見通しがたちにくいわけで す。以上のようなことがあるので、(建前として?)サブルーチン間のデータのや りとりは引数を渡して返り値をもらう、関数内ではローカル変数を利用するこ とで、サブルーチン同士の依存性をなくす、ということなのです。
ちなみに、このローカル変数は外部からはみえず、サブルーチンを抜けると無 くなってしまう、というのは、多くの場合スタックで実装しているということ から起因するわけなのですが、詳細はここでは略します(後に説明するかは未 定…)。
しかし、これはそのまま問題につながります。上でも述べている通り、ざっと プログラムを見ただけでは、そのグローバル変数がどこで変更されているかが すぐ分かりにくいからです。これはバグに直結する場合があります。
これらの要求から、オブジェクト指向へとつながっていきます。
狭義の抽象データ型とは、上でいうリストなどの、構造体などの機構を利用し てつくられる、現実の対象をイメージとして捉えやすくした=抽象化した型の ことをさします。さらにこれを一歩すすめると、プログラムを仮想的に「もの=オブジェク ト」のあつまりとして、そのオブジェクトの中身は一切関知せ ず、あくまでもその外部仕様のみをお互いに知っており、それらオブジェ クトの間の情報のやりとりで処理をすすめていく、という考え方がでてきまし た。この場合、それぞれのオブジェクトがしっかりと設計されていれば、相互 に干渉することはないので、プログラムが機能的にきちんと分離されます。さ らに、機能がはっきりしているのですからそれを部品化して再利用するのも容 易になるでしょう。
Xerox PARC の Smalltalk はこの思想(?)を忠実に実現しようとし たもので、とくに GUI (Graphical User Interface) を開発する上で、 部品化という意味でのとの相性(?)がよかったことで受け入れられることと なり、その流れが C++, Objective-C, Java などにつながっています。
その具体的な仕組みなのですが、
しかし、これもまたプログラミング手法としてみると、構造化言語ではうまく まとめて記述することが出来なかった似て非なるコードを一本化してまと める ための仕組みです。この仕組みを利用することで、似て非なるコー ドの「非なる」差分だけをコーディングすることが出来るようになり、コード の無駄をはぶき汎用性の高い部品とすることができ、再利用がしやす くなる、というわけです。