初めまして
皆さんこんばんは。
初めての投稿です。
普段はRで仕事をしているのですが、Rの理解を進めないともっと自由に扱えない様な気がしてきてしまった者です。
Rを中心に使ってはいますが、reticulateパッケージやscanpyのためにpythonをいじってみたり、Rcppのためにかすかな記憶を頼りにC++を書いたり、そんな毎日です。ここには、調べたり理解したいしたものを備忘録的に残していこうと思います。
さて、つらつらと自己紹介をしましたが、前置きを長く書いても仕方がないですね。
初投稿の内容なのですが、Rとは全く離れた「static」の話をしていこうと思います。
シリーズものにする予定で、のちのちRの話につながっていきます(断言)。
目標としてはrlangの話につなげようと思っています。
静的型付け言語なのに「static (=静的)」とは?
1. 大人の事情
「C言語系」というと、親のC言語をはじめ、C++、JAVA、C#などが思い浮かびます。
"C言語入門"
と書いてある本を読んで、
いきなり「おまじない」と言われてモヤッとするのは、まぁ鉄板ですが、
そこはとりあえず置いておいて読み進めると
+であったり>であったり、見たことがある記号が出てきて、これなら理解できるぞ!キラッ
となってるところにいきなり出てくるものがあります。
そう。
「static」
こいつです。
彗星のごとく現れたものの、本の中にはごまかす様に
「もう一度関数を呼び出してみましょう。数値が維持されてます!これがstaticの役割なんです。」
びっくりですよね。
なんも納得できないんですこのくだり。
初めてのプログラミング言語はCだったのですが、まさにこれでした。
何に使うんだよ。。。
と、思ったのを今でも覚えています。
ん-。。。
ホントに、なんなのかこれは???
裏側を知った今となっては、これを理解するには初級者に説明することが多くて入門書に書く内容にふさわしくなく、後回しにならざるを得ないのはわかります。
わかるのですが、気になる人って絶対にいると思うんですよね。
ということで、これまで理解することなく過ごしてきて、この前やっと腑に落ちる説明に出会えたので自分なりに表現してみよう!というのが今回の目的です。
2. コンパイラの目線から
コンパイラは、変数を見かけるとその型の大きさのメモリを確保します。
確保しておく時間はその変数のスコープが生きている間で十分です。
スコープから抜けると変数を使うことはできないからです。
一方で定数はどうでしょうか?
定数はコンパイラによって埋め込みの数値として処理されます。
なんで埋め込みにするのかといえば、その数値のサイズが、その定数が定義されているスコープの中で変わることはないからです。「定数」は変わることのない数値ですからね。つまり、プログラムをコンパイルした時点で何バイト確保しておけばいいかが決まりますし、確保しておくべき期間も最初から最後までと決まります。
グローバルスコープに定義するグローバル定数であれば、プログラムが動いている間は確保しておく必要があります。まぁ、一回一回、変わらないもののために領域確保の仕事するのはバカみたいですしね。。。
3. 変数だけどコンパイル時に確保してほしいことだってある
関数を実行すると、ローカル変数は記憶をなくしたように初めまして顔で毎回対応してくれます。
だから、毎回同じ数字を引数に渡せば同じ計算結果が帰ってきます。
関数が呼び出されると、毎回、関数が自由に使っていいメモリ領域をプレゼントされます。いわゆる、関数の「環境」というやつです。
環境、なんて言葉で難しく言って見えますが、関数のために呼び出し元とは別のメモリをプラスで使えるようにする仕組みのことです。これにローカル変数が記憶されていきます。
関数のためのメモリ領域なので、関数の仕事が終わってreturnされるとこのメモリはいらなくなって捨てられます。そしてまたこの関数が呼ばれると違うメモリ領域がプレゼントされて、、、の繰り返しです。
だから毎回関数は記憶喪失になるのです。
この領域は、関数の書き込まれているメモリ領域とは全く別のところです。
さて、話を戻すと、
定数と変数の差はコンパイル時に確保されるか実行時に確保されるか、の違いです。
コンパイラは効率重視なので、こういう差に敏感なのです。
定数はコンパイル時にプログラム自体に埋め込まれて、変数はプレゼントされたメモリに保管されます。
(グローバル変数は?と思ったそこのあなた。スバラシイデス。
正解は、一番大きいスコープの環境が用意されていて、main関数はmain関数の環境を持っていますし、そのグローバル環境も参照できる、という形です。)
さて、本題のstaticがここで登場します。
変数として宣言はしたいのですが、コンパイル時に場所の確保もしていてほしい!という何とも優柔不断なことも指定できるようにしておけば、柔軟性が高いと評価されます。いいですよね。高評価はうれしいですよね!
その指定方法として使われるのが「static」です。
プログラムを動かすOSからしてみたら、毎度沢山のメモリを関数呼び出しのたびにプログラムに与えているわけです。それが使いまわしたいからという理由で少なくて済むのです。
メモリ領域の資源管理がタスクのOSとしたら嬉しくないわけがないですね!!!
納得いきます?。。。。ですよね。
ここに関しては、別に大した理由はないと思っています。
C言語が制定されたときのことは全然知りません。ここからは想像のお話です。
昔のPCはスペックが低かったんです。メモリ資源も限られていました。
小さい容量をうまくやりくりする中で大きいメモリ領域の操作を小さく済むようにする魔法の言葉、これがstaticなんだと思います。
5. まとめ
色々見てきて、staticってこういう事かなぁというのを書き上げてみました。
staticが静的、と言われるのは、実行時にもう決まっているからじゃないでしょうか?
オブジェクト指向言語で静的プロパティというものがありますが、これはクラスオブジェクトのインスタンス化をしないで使えるプロパティの事です。インスタンスからでも使えて、どのインスタンスからでも同じ値や同じ関数を呼び出しているわけです。
なんでインスタンスが別でも同じものを使えるのでしょうか?
もうわかりますよね?静的プロパティはクラスがコンパイルされる際にもう保存領域が確保されているからです。
インスタンスの持つ環境ではなくて、クラスの仕様が定義されているコードの中にもう用意されていると考えれば、その領域に数値が入っていれば、インスタンスは自由に参照できます。どのインスタンスからでもです。その静的プロパティが変更されれば、どのインスタンスからも変更が確認できます。
関数は自分自身の設計図のあるメモリと環境の二つを見つめることができて、インスタンスは自分自身の設計図のオブジェクトのあるメモリと環境の二つを見つめることができるのです。
考え方ですね。
次回
環境について触れたので、Rにおける環境の話をしたいのですが、まだまだ勉強中なので骨子が固まったらまた書きたいと思います。
環境がでてくるとメタプログラミングの話にいったり、環境へのバインディングから非標準評価の話につながったりと忙しいです。。。
次-> (link)
(。。。書いたら更新しますね