このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

プログラマのためのJavaScript (3):参照について考えてみる

案の定、JavaScrip界隈でも用語法は混乱してますねー。僕は、言葉使いには割と神経質なほうで、用語の整理を試みたり造語をしたりして、……それでよけい混乱を助長したり、と、そんなことを以前の私的メモでも書きました(「あー、用語法は難しい!」)。

今回も「どうしようかなー」と悩んだ末、説明の方便として、用語の整理(若干の造語を含む)はすべきと判断しました。今回は「即値型」という言葉を導入して説明します。基本的なところから話をはじめます。つまんないかも知れないけど、JavaScript奇妙さに立ち向かうためには基礎固めも必要かもよ。

●コンピュータが扱うデータは所詮メモリブロック

コンピュータで扱えるデータは、結局のところ、メモリ内の特定の場所(特定のアドレス)からはじまる特定の長さ(つうか、幅つうか、サイズつうか)を持つ領域です。これをメモリブロックと呼んでおきましょう。

メモリブロックに格納された中身(content)が、整数値かポインター(アドレス値)か文字列か、などは、言語処理系やランタイム・システムが持つメタ情報により決定されます。メタ情報がなかったら、単なるビットコンビネーション(0と1の模様)に過ぎません、解釈できないわ。

もし、あるメモリブロックの一部がポインターだと分かれば、そのポインターをたどって(dereference)、別なメモリブロックに到着できます。それで、メモリ内の離れた位置にある(必ずしも連続してない)2つのブロックを関連付けることができるわけ。互いに関連するいくつかのブロックをまとめて、概念的には1つのデータとみなせることになります。複雑なデータは、メモリ内でパランパランに散在するブロック群をポインターで繋ぎ合わせたものですね、リンクリスト(linked list)なんて典型です。

●参照型と即値型

データが参照によって受け渡しされるような型は参照型って言います、世間一般で。参照型でない型は、基本型とかプリミティブ型とか呼んでいますが、これはどうもピンと来ないですね。そこで、ここでは“参照型でない型”を即値<そくち>型と呼ぶことにします。

「即値」は、もともとアセンブラの言葉でしょうか? コードに埋め込まれる定数リテラルってな意味合いです。言葉の感じとして、「それがそのまま、それ自体で値である」という雰囲気で、参照の反対語として適切だと僕は思うのです。(だから、これを使います。)

即値型データは、単一のメモリブロックによって表現されます。多くの場合は、メモリブロックの長さ(バイト長)も前もって一定に決まってます。例えば、整数値なら32ビット=4バイトとか。まー、即値でも不定長(可変長)のときもありますけどね。

即値型データの等値性(equality)は、メモリブロックの位置(開始アドレス、ひょっとしてレジスタに入っているかも知れない)とは無関係で、通常は、「中身のビットコンビネーションがまったく同じ」とき“等しい”と定義します。つまり、0-1模様として重ね合わせて一致するときに等しい、と。

それに対して参照型データは、参照(とりあえずポインターと思っていいです)を表す値を入れたメモリブロックと、参照先にあるメモリブロックの組としてデータが表現されます。もちろん、被参照ブロックが複雑な構造のハブになっているかもしれませんが、いちいちそれに言及するとメンドイので、データは「参照+被参照ブロック」だとしましょう。あと、ガーベッジコレクションによる移動とかも考えないことにしましょう、メンドイからね。

●参照/即値よりはミュータブル/イミュータブル

はい、基礎知識の準備はOK。こっから、JavaScriptの話ね。

JavaScriptでも、即値型と参照型の区別があって、(typeofによる分類の)number, boolean, string, undefinedの4つは即値型となっています。それと、値としてnullだけを持つNull型があり、これも即値型になります。

このなかで、stringが即値であることはちょっと驚きです。文字列はいくらでも長くなるので、処理系実装としては「参照+被参照ブロック」となるはずです。が、概念上は文字列データ全体が「それがそのまま、それ自体で値である」かのごとくコピーされると考えてよいわけ。

「コピーされると考えてよい」のだけど、実際にはたぶんコピーされない -- この事の本質は、参照か即値かという問題ではないのです。データのミュータビリティ(変更可能性)こそが核心ですね。イミュータブルなデータ(作ったらソレッキリ変更できない)なら、まるごとコピーしようが参照だけ渡そうが違いはありません。そもそも、文字列がイミュータブルだからこそ、「言語仕様では即値型で、実装では参照を使う」なんてことが可能なのです。

JavaScriptのような高水準言語では、データが即値か参照かなんてことは処理系の実装上の話題であって、言語仕様で云々<うんぬん>することじゃないっすよね。現状でも、オートボクシング(即値データ→参照データ変換)が強烈に働くので、次のようなことができます。


js> true.toString().charAt(0).toUpperCase()
T
js> (123).toString().substring(1, 3) * 10
230
js>

(123).toString()を解釈するとき、「即値123がラッパー・オブジェクトへの参照に自動変換されて、そのオブジェクトにメソッドtoStringを適用する」と考えるより、「整数123にメソッドtoStringを適用する」で十分でしょう。

現状でも、即値と参照を区別する必要はほとんどないし、JavaScript 2.0では実際にこの区別を止める方向のようです。(JavaScript 2.0が標準や実装にどの程度の影響を与えるかは分かりませんが。)

Unlike in JavaScript 1.5, there is no distinction between objects and primitive values. All values can have methods.

えっ、「そんなもん区別してなかったよ、即値と参照なんて知らんし」って。おや、そりゃまた失礼しました。あなたは正しい。

●今回のまとめ

  1. コンピュータで扱うデータは、とどのつまりは、特定の場所からはじまる特定の長さのメモリブロック。
  2. 複雑なデータは、ポインターを使ってパランパランのブロックを関連付けて表現する。
  3. “即値型データ”は単一メモリブロックで構成される。“参照型データ”は「参照(ポインター)+被参照ブロック」の組である。
  4. JavaScriptのstring型は即値型。だが、実装上はおそらく参照を使っている。
  5. 実は、参照/即値の区別よりミュータブル/イミュータブルの区別が大事である。
  6. 現状のJavaScripでも、参照/即値の区別を意識する場面はあまりない。将来はホントに区別がなくなるかもしれない。

いつまでも、データとデータ型じゃつまんないから、次回はオブジェクト構造についてでも。

ところで、データのミュータビリティは僕の“コダワリの話題”でして、次の2つの記事でも扱っています(題名だけだとなんの記事だか分かんないけど)。興味がある方は目を通してみてください。