rubykaigi2016

こんにちは高松です。
前回の記事で、『RubyKaigi2016』の概要についてご紹介しました。
今回の記事では、RubyKaigiで行われたセッションについて、抜粋してご紹介したいと思います!

Ruby3 Typing

初日一発目は、rubyの生みの親である、Matz こと まつもとゆきひろさんによるキーノートでした。
テーマは、「ruby3における型」についてです。

rubyの現在のメジャーバージョンは“2”であり、ruby3のリリース時期については特にアナウンスはされていません。
そこで、現在開発中であるruby3での型実装にの展望について、発表されていました。

rubyは「動的型付け言語」です。
そのために、プログラマーは型の指定を行うことなくプログラミングをすることができます。
これにより柔軟な実装ができ、rubyの代名詞とも言える「ダックタイピング」が可能になっています。
しかしその一方で、実行するまで何が入るかわからない、というデメリットも抱えています。

このデメリットは

  • 実行するまでわからないエラーが発生し得る
  • テストし忘れた機能はいつまでもtypeエラーが見つからない
  • 型が書いてないと読みづらい

といった弊害をもたらします。
3つめのデメリットはphpDocumentorなど、コメントやアノテーションを利用した対策が考えられますが、「そもそも動的型付けなのに、結局型書いてしまうのってどうなのだろう?」と感じてしまいます。

そのため、Matzさんは、オブジェクトの「“ふるまい”による型付け」について構想を練っているようです。
これは、GO言語のstructural typingに近い考えで、そこからさらにinterfaceを取り除いたようなものだそうです。
つまり、「それが〜型だよ」という名付けをせずに、“ふるまい”だけで型を推論できるようにするものです。

rubyは動的にメソッドを書き換えたりできてしまうので、これだけで完全な型推論は難しいと思いますが、Matzさんによれば、「100%のカバレッジは無理でも0%よりはマシ」ということだそうです。
これによって、コンパイルエラーのあるduck typingを実現したいということですね。

いずれにせよ、まだ構想の段階で動くものがないそうなので、今後の展開に期待しています。
ちなみに、「ruby3は、いつになるかわからないけれど、東京オリンピックまでには出したい」とのことでした。

Unifying Fixnum and Bignum into Integer

こちらはrubyコミッターの田中哲さんのセッションです。
ruby2.4から、FixnumとBignumがIntegerに統合されてしまうお話です。

現在のrubyでは、整数を表す型として、FixnumとBignumの二種類が存在しています。
通常はFixnum、比較的大きな数字をBignumで扱うという区別になっていますが、実はそれぞれの範囲は処理系によって変わってしまいます。
例えば、まず32bit環境と64bit環境で異なりますし、同じ64bitでもCRubyとJRubyで異なります。
メモリの扱える範囲が違うので当然といえば当然なのですが、CRubyとJRubyで違うのは知りませんでした。
これは少しややこしいですね。

さらに、実はFixnumとBignum、ISOに定められたrubyの仕様には載ってないのだそうです。
Integerを実装するときの具体案という扱いということでした。
Integerを分割してはいけないという記述はないのですが、なんとなく気になります。

また、FixnumとBignumを統合することによって

  • 学習コストが下がる
  • 間違えた使い方ができなくなる
  • ドキュメントの単純化ができる

といったメリットがあるということで、今回の統合に踏み切ることになったそうです。

学習コストが下がるということですが、確かに、初めてrubyを勉強したとき、FixnumとBignum分かれていてややこしいなと思った記憶があります。
Fixnumはこうで、Bignumはこうで・・・というような説明が無くなって、「整数はInteger」と一言で言えてしまえるほうが初学者に優しいのは間違いないです。

ドキュメントの単純化というのは、これと似たような意味で、FixnumとBignumふたつ分のドキュメントがIntegerのものだけになるなら、そちらの方が楽に決まっています。
間違えた使い方というのは、例えば、「数値をvalidateする際に、整数であることを保証したいのにFixnumの範囲を使ってvalidateしてしまう」というような使い方です。
これが何故間違えているかというと、Fixnumは「特定の範囲の整数」を表す型であり、「全ての整数」を表す型では無いからです。

もちろん、メモリは有限なのでIntegerも実際には「すべての整数」を表すことはできないのですが、プログラムの範囲では「(メモリが許す限り)全ての整数」を表す型ですので、適切な使い方となります。
既存のコードを、変更に対応させるコストはあるとは思いますが、ある程度の下位互換は考慮されているようですし、この変更は個人的にはとても気に入りました。

Optimizing Ruby

こちらはrubyコアコミッターの卜部昌平さんのセッションです。

rubyは正直遅いです。
メジャーな言語の中でも下から数えた方が早いくらい、遅いです。(最近PHPも速くなりましたし!)
その理由は、ローレイヤーで最適化がなされていないからだそうです。

このセッションは、rubyに“最適化”を適用して速度を上げようという話でした。
そもそもrubyが最適化されていないのは、メソッドが動的に再定義される可能性があるからだそうです。

しかしながら、たとえばInteger#+などはあまり再定義されることはありません。
そこで、“deoptimization”というアイディアを考えたそうです。
deoptimizationとは、「非最適化」のことです。

具体的には「最初に再定義を考慮せずにすべて最適化してしまい、再定義があった場合に非最適化する」というアイディアです。
僕は、最初は「なぜ“最適化”の話をしているのに、“非最適化”の話を始めるんだろう」と思ったのですが、なるほど、「一部分だけ非最適化することで、最適化の問題を回避しよう」ということだったのです。

この方法は、rubyの実装である“C”のレベルで行われるため移植性が高く、また、オーバーヘッドもほぼ無いそうです。
欠点としては、「evalやblockが使われていると不利になる」点などが挙げられるようですが、これは適用されるプログラム次第なので、なんとも言えないところでしょう。

実際、似たような機構を持っているJRubyはCRubyよりも速い場合が多いので、割と効果はあるのかもしれませんね。
前述したとおり、最適化効率は適用されるプログラム次第ですし、その際の非最適化コストは余計にかかるわけで、確実な最適化にはあと一歩といったところでしょうか。
ただ、他の最適化手法を適用する余地もまだありで、これからの進展が期待されます。
いずれにせよ、投入されるのは「早くてruby3から」ということなので、まだまだ先の話になりそうです。

各セッションを見て感じたこと

rubyやgemを実際に作っている人達の話ということもあって、とても高度で興味深いセッションばかりでした。
ローレイヤーの深くまで入りこんだ話は理解が追いつかない部分もありましたが、それでも全体的に話はわかりやすく、飽きずに聞くことができたので、「やはり場慣れした人たちは違うな」と感じました。

今回発表されたRuby3の新機能や、gemは、どれも現在のプログラム開発のトレンドに追いついていたり、中には先んじるものもあって、やはりrubyはまだまだ熱い言語であると再認識することができました。
しばらくプロダクションレベルでrubyを使用していませんが、負けずにrubyで良いものをつくっていきたいと思いました。