世界線航跡蔵

Mad web programmerのYuguiが技術ネタや日々のあれこれをお送りします。

2008年02月25日

シンボルとは何か その1(後編) - 文字列のintern

シリーズ・RubyのSymbol。だいぶ空いてしまったけど、気が向いたので続きを書く。

前回は文字列の同一性について復習したのであった。

意義

そう言うわけで、文字列においては同一性と同値性は異なる。特に、Rubyの場合は同じリテラルも評価する度に異なるオブジェクトを生成する。ところが、これは不便な場合があるわけだ。

まず、文字列の同値性比較はコストがかかる。長い文字列を比較にするには時間が掛かる。保持しておくにも長い文字列だったらメモリーを食う。更に、毎回リテラルからオブジェクトを生成するとしたら、無駄なケースが多々ある。Railsに良く出てくる疑似名前付き引数みたいなやつ。

some_method "a" => 1, "b" => 2, "c" => 3

おい、この箇所を通る度に一々文字列のメモリー確保してオブジェクト構築するのか? その背後ではパフォーマンス厨なら誰もが恐れるmalloc(3)が動いているというのに?

ま、文字列本体についてはRuby処理系もそんなに馬鹿じゃなくて、実際にはもう少し効率の良い処理をする(のだったと思う。確か)。でも内部でRString構造体の確保が毎回必要になるのは本当だ。

とにかく、文字列が含んでいる「文字の列」部分を確保して保持しておくのは色々大変だ。最小限に抑えたい。そこで、internする。

intern操作

intern操作によって、文字列はオブジェクトとして一意になる。だから、同一性判定するだけで低コストで比較できる。

10.times do
  p "foo".object_id
end

すると毎回違う結果が出るが、

10.times do
  p "foo".intern.object_id
end

は同じ結果がずらりと並ぶ。この「文字列をinternした結果」こそがSymbolオブジェクトなのである。

internというのは別にRuby固有の話ではない。Javaにだって、String#intern(がある。返ってくるのもStringオブジェクトであるっていう点がRubyと違うけれども。でも、「同値性の判定を同一性で済ませたい」というニーズは言語に依らずにある話。

そう言う感じで、Javaにとっては「文字列をinternしたもの」は文字列そのものだ。前回、文字列リテラルの同一性比較がtrueだったのも、Javaの場合は文字列リテラルはあらかじめinternされているからだ。

そう言う意味で、Symbolは「internされた文字列」に限りなく近い。違うのは、同一性と同値性が同義であることと、変更不能であることぐらいだ。変更可能だったら同一性と同値性の一致が知らない間に崩れていたりして困るからね。

それに、Rubyにしたってしばらく前に1.9ではSymbolStringのサブクラスだった。Matzがなんか、実装しちゃったのだ。私は大反対の立場で、まぁ、諸々の反対とバグが沢山出たことで取りやめになったけど。

メモリー

同じ内容のシンボルは常にオブジェクトとして同一である。従って、

10.times do
 :foo
end

これは新たなオブジェクトを生成したりしない。詳しいことは次回扱うけれども、:fooみたいなシンボルリテラルの実体はRubyがソースコードを解析した時点で解決される。実行時にはメモリーの確保を伴わない。だから、速いしメモリーを食わない。

何故Railsがシンボルをいっぱい使っているのか? 1つの答えはこれだろう。

シンボルとは

シンボルとは何か。答えの1つはこれだ。

  • 変更できない「文字列のようなもの」
    • 変更のためのメソッドを持っていない
    • 同値ならば、必ず同一である

トラックバック

http://yugui.jp/articles/755/ping

現在のところトラックバックはありません

コメント

Easylife (2008年02月25日 20時45分57秒)

知らなかったです。
すごく為になりました。

blog comments powered by Disqus

ご案内

前の記事
次の記事

タグ一覧

過去ログ

  1. 2010年06月
  2. 2010年04月
  3. 2010年02月
  4. 2010年01月
  5. 過去ログ一覧

フィード

フィードとは

その他

Powered by "rhianolethe" the blog system