31
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Ruby 2.4でIntegerに一本化される整数

Last updated at Posted at 2016-09-18

Ruby 2.4から、整数のクラスが付け変わることになりますが、特にCエクステンションを書いている場合は注意の必要があります。

Ruby 2.3までの世界

Rubyの世界にももちろん整数がありますが、(Ruby側から見て)今までは抽象クラスのIntegerの下に、絶対値の小さな整数についてはFixnum、それに収まらないものについてはBignumという具象クラスがある、というように分かれていました。このあたりについては、以前書いた記事が参考になるかと思います。

問題点

このような形にしていることで、いくつか問題がありました。

  • FixnumBignumは実装の詳細の違いで、Ruby側から違いが見える必然性はない
  • 同じ整数なのにFixnumBignumで挙動を違える、なんてことはむしろやるべきでない
  • 環境によってFixnumのサイズが違う(可搬性に乏しい)
  • RubyのISO規格上も、Integer以下は実装依存となっている

Ruby 2.4での変更点

そんなこともあって、Ruby 2.4からは両者がIntegerへ統合されることになりました。

Ruby側から見て

ふつうにプログラムを書いている中では、そもそもFixnumBignumを直接使う場面自体が少なかったでしょうし、そこまで大問題とはならないと思いますが、いくつか注意すべき点はあります。

既存のプログラムとの互換上、FixnumBignumという定数は存在し続けますが、どちらも**Integerのエイリアス**となります。それぞれをオープンクラスなどしていた場合も、直接Integerを変更するような形となります(きちんと対応する形に修正した方がいいでしょう)。

そして、foo.is_a?(Fixnum)のようにFixnumに収まるかチェックしていた場合、Ruby 2.4ではfoo.is_a?(Integer)とみなされて、整数であれば常にtrueとなります。(Cエクステンションが絡むような状況なら別として)Fixnumかどうかをチェックするという意図自体が根本的に問題なので、きちんと範囲チェックするように修正しましょう。

あと、これは実際に影響する場面もあるかもしれませんが、FixnumBignumという定数そのものをDSLの一部に使っていた場合、Integerと同じ値になってしまうのでうまく動かなくなります。使っているgemの説明に従って、適切に置き換えましょう。

C言語側から見て

Ruby上ではFixnumBignumの区別は廃止されましたが、C言語の世界では2種類の内部構造がそのまま存続する形となっています。ということで、「整数を扱う部分をすべて書き換える必要がある」なんてことにはなりません。

ただし、C言語上ではFixnumBignumを表すrb_cFixnumrb_cBignum廃止されています。これらの定数を使っていた場合、コンパイルエラーとなります。代替策としては、

  • 型チェックに使っていた場合→FIXNUM_P1RB_TYPE_Pなどで置き換えましょう。内部データ構造を示すためのT_BIGNUMは健在です。
  • メソッド定義などをしていた場合→Integerrb_cInteger)にセットする形に切り替えましょう。Fixnum用とBignum用の関数が別にある場合、内部で振り分けする必要が出てきます。

また、これらの振り分けを支援するための定数として、RUBY_INTEGER_UNIFICATIONが定義されています。#ifdef RUBY_INTEGER_UNIFICATIONで切り分けましょう。

自作gemのチェック

以前に作っていたjkr2255/bit_utils解説)について、コードをチェックしてみましたが、内部的にはFixnum用とBignum用のメソッドがあって、

  • Fixnum用…Bignumを投げるとエラーになる
  • Bignum用…Fixnumでも動くけど、少し余分な処理が入る

というようになっていました。そして、Fixnumをオープンして使うとき以外はBignum用をそのまま使うようになっていて、オープンクラス時もFixnumBignumの順で行っていたので、そのままですべてがうまくいくような流れになっていました。Ruby 2.4.0-preview2でも正常に動作しました。

とはいえ、FixnumBignumを両方オープンしているのも行儀が悪いので、書き換えを行う予定です。

参考資料

RubyKaigiで発表されたスライドのPDF

  1. 1ビットを見るだけなので、きわめて高速です。

31
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?