Rubyがどんな風に動いてるのか調べてみた（Fixnum,"+",fix_plus）その①

Ruby歴が1年くらいのエンジニアです！
最近ようやくRubyがどういう風に動いてるのかに興味が出てきたので、Rubyのコア部分のコードを頑張って読んでみる事にしました。
最終的には、コミット出来るところまでいけたら最高だなと思っています。（不定期更新です）

## 準備

現在の安定版は 2.3.1のようなので、2.3.1で勉強していきたいと思います。

ソースコードのダウンロードはこちらから
https://www.ruby-lang.org/ja/downloads/

Documentはこちらを参考にしたり、ググったりです
http://docs.ruby-lang.org/ja/2.3.0/class/Object.html

## 第一印象

意気揚々とダウンロードして読み始めたのですが

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">最近ようやっとrubyのコアの部分のコードをちょっとずつ見てるんだけど、さっぱりわからん笑<br><br>どこから読み始めたらいいんや笑</p>&mdash; takuji (@cat__tac) <a href="https://twitter.com/cat__tac/status/730243483030577152">2016年5月11日</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>


という感じです笑
なので、本当にのんびりな進みになると思うので、生温い目で見守っていてください笑

## 足がかり

辛さを感じながら、Cのソースコードを読んで行くと

`rb_define_method`

という、いかにもmethodを定義してそうなコードを見つけました。
これだ！と想い、`git grep "rb_define_method"`で検索してみると、出てくる出てくる！

<img width="1081" alt="スクリーンショット 2016-05-11 13.51.30.png" src="https://qiita-image-store.s3.amazonaws.com/0/23873/f905ee56-aff8-fc89-2279-27ad892047b7.png">

見た事ある単語も出てきて、だいぶ安心しました笑

webで検索しても出てきました。
http://rurema.clear-code.com/query:rb_define_method/version:2.3.0/

ただしくは
`void rb_define_method(VALUE klass, const char *name, VALUE(*func)(), int argc)`が正しいらしいです。

 - klassがメソッドが所属するクラス
 - *nameが、インスタンスメソッドの名前
 - *funcが、どんな挙動をするか
 - argcが、メソッドの引数の数

のようです！
これがわかったところで簡単そうなメソッドを読んでみます


## Numeric.cのfix_plusについて読んでみる
 
今回は以下のメソッドについて深めて行きたいと思います。
`rb_define_method(rb_cFixnum, "+", fix_plus, 1);`

まず、numeric.c内でrb_cFixnumで検索をかけるとたくさん出てきます。

<img width="660" alt="スクリーンショット 2016-05-11 14.01.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/23873/50f8cd26-68df-c6fb-16fc-5d1d68f7e3b6.png">

で、これを見てみると、

`rb_cFixnum = rb_define_class("Fixnum", rb_cInteger);`というまたまたいかにも、クラスを定義してそうなコードを発見しました。

ここに書かれている、rb_cIntegerを検索すると

`rb_cInteger = rb_define_class("Integer", rb_cNumeric);`

が出てきました。
どんどん、クラスが継承されていっているみたいです。

さらに、掘って行きます。

`rb_cNumeric = rb_define_class("Numeric", rb_cObject);`

が出てきました。
で、rb_cObjectを調べると**object.cファイルの3378行目**にありました。

`rb_cObject = rb_define_class("Object", rb_cBasicObject);`

で、rb_cBasicObjectを調べると

`rb_cBasicObject = rb_define_class("BasicObject", Qnil);`

### Qnilってなんだ！！

と思ったら、
ここのWEBサイトにかいてありました。
http://ruby.gfd-dennou.org/tutorial/ruby-ext/

> Rubyから直接呼び出す関数は戻り値としてRubyのオブジェクトを返す 必要があります。 今は特に何も戻り値が必要でないので、Rubyの「nil」に 対応する「Qnil」という定数を与えています。

というわけで、**rb_cBasicObject**が一番元のクラスだという事が判明しました。

階層的には

rb_cBasicObject
↓
rb_cObject
↓
rb_cNumeric
↓
rb_cInteger
↓
rb_cFixnum

という、継承構造のようです。

## 本題のfix_plusの方を調べて行きたいと思います。

`rb_define_method(rb_cFixnum, "+", fix_plus, 1);`

rb_cFixnumというクラスに、+という名前で、fix_plusの挙動を定義します。で、引数はひとつです。

### では、fix_plusの挙動について調べましょう。

```c:numeric.c
static VALUE
fix_plus(VALUE x, VALUE y)
{
    if (FIXNUM_P(y)) {
	long a, b, c;
	VALUE r;

	a = FIX2LONG(x);
	b = FIX2LONG(y);
	c = a + b;
	r = LONG2NUM(c);

	return r;
    }
    else if (RB_TYPE_P(y, T_BIGNUM)) {
	return rb_big_plus(y, x);
    }
    else if (RB_TYPE_P(y, T_FLOAT)) {
	return DBL2NUM((double)FIX2LONG(x) + RFLOAT_VALUE(y));
    }
    else if (RB_TYPE_P(y, T_COMPLEX)) {
	VALUE rb_nucomp_add(VALUE, VALUE);
	return rb_nucomp_add(y, x);
    }
    else {
	return rb_num_coerce_bin(x, y, '+');
    }
}
```

引数２つじゃね？とおもったのですが、0が１で、1が２的なあれかなと、とりあえず思って今は流しておきたいと思います。判明したら、正しく書きます。

+だから簡単かなと思ったら、意外とたくさん条件分岐があって面食らっています笑

### FIXNUM_P(y)とは！？

検索したらでてきました。関数の用です（version違うけどきっと同じだと思われます。）
http://docs.ruby-lang.org/ja/1.9.3/function/FIXNUM_P.html

というわけで、yがFIXNUMだとtrueが返るようです。

## yがFIXNUMの場合

`FIX2LONG`この関数は見た目からして、型をFIXNUMをLONGにするやつっぽいのでそういう認識で活きます。

`LONG2NUM`この関数も、型をLONGからNUMに返る奴でしょう。

## まとめ

このメソッドは
`rb_define_method(rb_cFixnum, "+", fix_plus, 1)`

Fixnumというクラスに対して、+が呼ばれた時に

引数yがFIXNUMの時、
引数xと引数yをまず、LONG型に変換し、足し算してから、返り値として、NUM型のrを返すというメソッドを定義する

という、もののようです。

実際に読んでみると意外なんとかなるなという印象です。（これであっていれば笑）
きっと難しいところはめっちゃ難しいんだと思いますがちょっとずつ頑張って行こうと思います。