Mae向きなブログ

Mae向きな情報発信を続けていきたいと思います。

Rubyのしくみ -Ruby Under a Microscope-

世の中にはたくさんのプログラミング言語が存在しています。学生時代に初めてPascalに触れてから今まで、何種類かの言語を触ってはあきらめを繰り返してきましたが、自分にとってRubyはなぜか学習し続けたい言語になっています。

本書は、Rubyのしくみを知りたくて2014年12月に購入したのですが、途中で挫折しながらもようやく読み進めることができました。8章以降(以前も)はまだまだ理解が不完全なところが多いので、折を見て読み返してみたいと思っています。

本書を通して学んだことはいくつもありますが、中でもRubyの内部を自分の目と手で探ってみたいと思えるようになったことが一番の収穫かなと思っています。

例えば、第7章「ハッシュテーブル:Ruby内部の働き者」については自分でも実験をしてみたのですが、そこから自分の学習をさらに進めることができました。

実験2:さまざまなサイズのハッシュに新しい要素を1つ追加する

実験2はエントリの再ハッシュ、または再分散が実際に起こるかをどうかをテストする1つの手法として紹介されていますが、自分の環境(MacBook Pro (Retina, 13-inch, Late 2013), ruby 2.3.0dev)だと、以下のようなグラフになりました。

f:id:rahaema:20151228140749p:plain

p200の図7-8のグラフでは、1番目と7番目の挿入において2つの小さなスパイク、57番目と97番目の挿入時に大きなスパイクが見えますが、上のグラフとは明らかに傾向が違っているように見えます。

実際、st.c を見てみると、p201で示されているようなprimes配列ではなくて、2のべき乗をハッシュテーブルのバケット数にしていることがわかりました。今まで、ハッシュのバケット値は素数が使われるのが当然と思っていましたし、解説でも「Rubyはハッシュテーブルのバケット値を素数に設定する」とありましたので、これは意外なことでした。

本が書かれた後に遅い剰余演算をやめて、2のべき乗を使うことになったようです(以下参照)。

st.c

static st_index_t
next_pow2(st_index_t x)
{
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;
#if SIZEOF_ST_INDEX_T == 8
    x |= x >> 32;
#endif
    return x + 1;
}

static st_index_t
new_size(st_index_t size)
{
    st_index_t n;

    if (size && (size & ~(size - 1)) == size) /* already a power-of-two? */
        return size;

    n = next_pow2(size);
    if (n > size)
        return n;
#ifndef NOT_RUBY
    rb_raise(rb_eRuntimeError, "st_table too big");
#endif
    return -1;                  /* should raise exception */
}

Rubyについて深く学んでみたいと思ったのが、本書を読むきっかけですが、ハッシュ法やC言語についても学ぶ良いきっかけにもなりました。

  • next_pow2関数でのxより大きな2のべき乗の求め方
  • new_size関数内の2のべき乗かどうかの判定

なども興味深いものでした。

お礼

今回、学習を進めるにあたって、twitter上で @finalfusionさんから多くのアドバイスをいただきました(以下参照)。

身近で質問をするとか議論をするといったことができる環境にない中で学習を進めるのは、中々難しいことですが、twitterなどを活用することで学習ができることはありがたいことだと感じます。

Rubyのしくみ -Ruby Under a Microscope-

Rubyのしくみ -Ruby Under a Microscope-