今回は変数です.変数というのは計算の中間状態を取っておく箱,というような説明をしますね.でも,もっと深い話もあるんですよ.
まずはやっぱり機械語の話からしましょうか.これも新刊「さわるようにしくみがわかるコンピュータのひみつ」 でも説明していることですが,さくっと.機械語の命令を並べることがコンピュータを動かすことだったわけですが,機械語ができることは本当に単純なことしかできません.命令には計算することの他に前回のGOTOがありました.今日紹介するのは,計算の中間状態をメモリーに取っておく,メモリーから読み出す,という命令です.数をあっちからこっちに移動するようなのも命令としてあるんですね.
そのとき,メモリーというのは番地で指し示しますから,1000番地にとっておく,とか1000番地から読み出す,というように使います.こういう命令を組み合わせると,大体どんな計算でもできるようになります.
当然ながら,1000番地という言い方は何を指し示しているかわからなくなるので,1000番地に名前をつけます.それが変数です.たとえば「さいふ」という名前をつけたとすると,いま財布に入っているお金がいくらかということになります.100円の買い物をしたら.
さいふから読み出す
100を引く
さいふにとっておく
こんな感じでプログラムをつくれば,さいふのお金が100円減ります.実際はさいふに100円以上のお金が入っていなければダメなのでそれをチェックするプログラムも必要ですけども.
こういうメモリーに名前をつけたものが変数ですが,この後いろんな拡張がされました.
まずはメモリーの1つの箱のサイズです.1バイトというのが普通のコンピュータのメモリーの1つの箱のサイズのことです.1バイトは8ビットつまり8桁の0か1で表す数なので,0から255までの数です.実は最近のコンピュータはメモリーの1つの箱は64ビットつまり8バイトもあるんですが.箱のサイズが変わると,古いコンピュータのプログラムが動かなくなってしまうので,プログラムからみた箱のサイズは1バイトのままになってます.すると,「さいふ」という変数はメモリーの1000番地を指し示しているとしても,本当は1000番地だけなのか,1000番地から1007番地までの8バイトを1つの箱として考えるのか(他にも2バイト,4バイトの区切り方があります)ということも指定しなければなりません.実はたしざんの命令も,1バイト同士の足し算なのか,2バイト,4バイト,8バイト同士の足し算なのか,全部ちがう命令です.
1つの変数に8バイト入れられたとしても,それだけでは不十分です.たとえば僕の名前は「原田康徳」と言いますが,漢字は1文字2バイトなので4つの漢字で8バイトです.もっと文字数の多い名前の人は1つの変数に入れられません.というより4文字以上のものなんていくらでもあるんでどうしたらよいでしょう.メモリーの箱の大きさよりも大きなデータに対して名前をつけたい,という問題です.
そこで発明されたのがポインタです.たとえば,「住所」という変数があったとします.この変数にはメモリーの番地が入っています.その番地を見ると,そこには本当に変数に入れたい住所 「新宿区...」という文字がメモリーに順番に入っています.変数に入っているのはこういう文字の先頭の番地ですが,この住所はどこで終わるかがわからないとまずいですね.そのため,文字の数字表現で絶対に出てこない数(たとえば 0)を入れて,そこで文字が終わりにします.この方法だといくらでも長い文字を変数に入れられます.他には,たとえば変数が指している番地の最初には文字の長さ(例えば11)が入っていて,その次から11文字分が「住所」というやりかたもあります.
この「住所」は文字しか入りませんが,いろんな種類のデータを入れられる変数があると便利ですよね.例えば「顔」という変数にはその人の顔写真の画像が入っているかもしれないし,画像がない場合はその人の名前の文字が入っているかもしれません.こういうのも1つの変数で表したい.
そういう場合は,メモリー側にこのデータはどんな種類か(画像か文字か)を示す情報も入れておきます.そうすると,何かメモリーの番地があると,それだけでどんな情報を示しているのかがわかります.
実は,裸のコンピュータではそんなことをしません.メモリーには数しか入らなくて,その数をなんだと解釈して命令を実行するかを自分でちゃんと頭にいれてプログラムを作らないとダメだったんです.で,結構間違うので,コンピュータが暴走したりフリーズしたりしました.今はほとんどなくなりましたよね.それはメモリーにそのメモリーを解釈する情報も一緒に置くようになったからです.
変数はいろんな情報をとっておいたり読み出したりするものですが,さらに面白い発明があります.機械語の延長で考えると,1つの変数に入れる値がどんどん変化する,と考えるのが普通です.しかし,この,変化するせいでプログラムがとてもわかりにくくもなります.もし,変数には値を1回しか入れることができなくて,1度値を入れてしまったら,もう変更はできない.ということにしたらどうなるでしょう.そんなんじゃまともなプログラムを作れないと一瞬思うのですが.案外そうじゃないんです.
プログラムの中の変数は,複雑な計算を何回もやるのは勿体無いので1回計算したものをとっておいて,それを何度も読み出して再利用するということが結構行われます.これなんかは,最初に計算をした時に変数に値を入れたあとは,もう変わりません.むしろ変わって欲しくないですよね.そんな計算の中間状態をとっておくような変数なんて,何度も再利用するんじゃなくて,どんどん使い捨てて行くほうが自然です.だって,さっきこの変数はこの計算を代表したけど,いまは違う,なんてことをいちいち考えたくないからです.
というわけで,一回しか値を入れることができない変数という発明がありました.この変数は(値が決まっていない,何かの値)という2つの状態があるということです.
すごい変数の話はまだまだ続きます.
値が決まっていない変数を読み出そうとしたらどういうことが起きるでしょうか.普通はエラーですよね.でもそれはプログラムが順番に実行していたときの話です.今はプログラムが同時にいくつも走ります.それらのプログラムの実行がどっちが速いかなんて,いろんな条件で変わるので,一斉に走らせるたびにどっちが速いかなんて毎回変わります.プログラムAが変数に値を書き込みます.プログラムBはその変数から値をよみます.もしプログラムBの実行が速かったら,エラーでいいのでしょうか.
それをエラーにしたくないので,普通は,プログラムAが変数に値を書き込むのを待ってからプログラムBがそれを読むようにします.Bが変数を使う直前で実行を待ちます.Aが計算が終わって変数にセットしたあとBに「終わりました」というメッセージを送ります.そうすれば,変数を読み出すエラーを防げます.
こういうメッセージのやりとりも,結構間違えが多くなるんです.そこで,画期的な発明は,もし値が決まっていない変数を読み出そうとしたら,そこで実行を一旦止めるというやりかたです.で,誰かが値を書き込んだと同時に,止まっているプログラムは起こされて続きを実行します.このやり方の何がすごいって,いちいち待つとか終わったよといったやりとりを明示的にやらなくても,変数の参照関係で勝手にそのやりとりをやってくれるということです.
さらにすごいのがあります.プログラムBは変数を使うけどもその中身については気にしないような処理をするんだとしましょう.そんなときは変数の中身が決まっていないのに,どんどん本当に必要になるまでどんどん計算を先に進められるということです.
たとえば,何かの申請書を書いて許可をもらうとしましょう.このとき,承認する人は4人いて,本来ならば申請書に全部記入してから順番に4人から承認をもらわなければならないのですが.4人はそれぞれ調べる役割が違います.一人は申請する人が確かにその土地に住んでいるかを調べます.別の一人は申請書の理由が正当であるかを調べます.この人はちゃんと住んでいるかどうかのチェックはしません.
理由を調べる人の仕事はムラがあります.判断に時間がかかるからですが,その申請が滅多にこないので,同じような申請が続けばすごく待たされるかもしれません.それに対して住んでいるかどうかを調べる仕事は,短時間で調べられるのと,そのチェックの仕事がほぼ均一にくるので,だいたいどれくらいの時間待たされるのか先が読めます.
この時,まず申請書には理由を書きます.理由を書き終わった段階で,名前や住所は未記入ですぐに申請にだします.理由を調べる人が空いていればすぐにチェックしてもらえます.その間に,ゆっくりと名前や住所を書きます.書き終わり次第住所を調べる人もチェックしてくれます.
随分と長い例ですみませんでしたが,これ,「待って」「終わったよ」というやり方では,プログラムがぐちゃぐちゃになります.というかそもそもお役所だったら,全員の申請をできるだけ早くなんて考えないから,全部埋まってから順番に,というプログラムしかありえません.ところが,値が決まっていない変数を読み出したらまつ,という仕組みがあると,プログラムはすっきりとしたままで,非常に効率よく全体が動くようになります.
その決まっていない状態は伝搬できます.
A=B
というのはBの値をAに入れるということですが,Bの値が決まっていない場合,ここでは値が知りたいわけではなくて,AはBと同じということを言いたいだけですから,そのまま実行できます.そしてAの値をちゃんと知りたくなったときにまだ決まっていなければ待ちます.
中学校の技術でネットワークの通信のプログラミングをやるらしいですが,こういうすごい変数を使った言語をつかえば,実に簡単に高性能なものが作れそうなんですけども.