Money Forward Developers Blog

株式会社マネーフォワード公式開発者向けブログです。技術や開発手法、イベント登壇などを発信します。サービスに関するご質問は、各サービス窓口までご連絡ください。

20230215130734

最近のruby-core (2017年3月)

こんにちは。卜部です。

ruby-coreというRuby本体の開発の議論がされているメーリングリストがあります。

新機能やバグ報告などがだいたいここに集約されてくるので購読しておくとRubyの動きが分かります。

ちょっと間が開いてしまいましたが、最近興味深かったトピックを紹介します。

[#13188] Reinitialize Ruby VM.

いま、Rubyのプロセスが立ち上がったときに初期化が走っているわけですけれども、そのあともう一回初期化しようとしてもできないという問題があります。これができずに困る代表的な例としてmod_rubyや類似のシステムがあります。

なんでかというとソースコード中にさまざまなグローバル変数が綺羅星のように散りばめられているため、それらを一旦リセットするというのが難しい。

まあ、どうしてそうなったかというと、なにもかもが二十年以上前の設計だからというよりなく、設計が現代的ではない点に関しては今更しょうがないです。

とはいうものの実需に応えられないのは問題でありまして、なんとかしたく思ってはいる。思ってはいるんだけどどうしようかな、という感じです。

[#5481] Gemifying Ruby standard library

しばらくこの連載の間が開いていたうちに標準添付ライブラリのgem化がだいぶ進んできました。

マイナーなトラブルはポツポツとはありますが、一応いまのところブロッカーになるような大きなものは出ていないので、このまま行けば多くのライブラリがgemになった状態で2.5が出るかもしれませんね。

[#13072] Current state of date standard library

みなさんも日々お使いかと思うDate標準ライブラリですが、現在、実は、メンテナンスされていません。

まあそれでもさほど困らず使えているのは、もともとの完成度の高さを示しているという事はできると思います。

とはいうものの、細かいバグなどは存在するが、放置されているし、仕様の議論などは行うべくもない状況なので、今のままだと不幸でしかないですね。そこで、どうしようかという議論になっています。

[#13045] Passing a Hash with String keys as keyword arguments

キーワード引数は顕著に便利な機能なので使いたいのですが、文字列をキーとして使う、ようは普通のハッシュを渡そうとするときに、いちいち変換を(手で)書かねばならず、面倒です。

その問題意識はよく理解できるのだけれど、そこでじゃあハッシュが直接渡せるようにしてほしいというこのリクエストはちょっと筋が悪かった。 文字列とシンボルを同じように扱いたいかどうかはプログラマの側の意図なのであって、言語でそれを決めつけるのはやっぱりよくないわけです。

なので、キーワード引数で対処するんじゃなくて、ハッシュをうまく変換できるメソッドがあればいいんじゃないかという方向で提案してください、となりました。

[#8661] Add option to print backstrace in reverse order(stack frames first & error last)

だれも大騒ぎしてなくてたぶんみんな気づいてないんだと思うんですが、バックトレースの表示順が逆になったんですよね。

もとの動機はというと、(昔と違って)最近のプログラムは大規模なので、全般的に言ってスタックトレースが長いという問題があります。Railsでいうと、まずUnicornがあって、Rackがあって、その上にRailsが乗ってて、みたいな。そこで、バックトレースを表示すると、ばーっと表示されて画面から流れていくわけだけれど、あまりに長すぎて核心の部分が遥か上空にある。なのでスクロールして戻さないといけなくて、これは不便なわけですよ。なので、スクロールしなくても最後の方に核心部分がきてほしい。これがリクエストです。

ただ、そのまま実装してしまうと、これは当然、これまでの順序で受け取ることを期待している他のアプリが動かなくなってしまうという重大な問題があり、これを回避しないといけません。もとの提案はオプションで、とあるけれど、これもNGで、他のプログラムがバックトレースを読むという前提でいうと、オプションなんて他のプログラムがコントロールできないじゃないですか。だから読む側としてはどっち順で流れてくるか判定不能になってしまうので、オプションはよくない。

そこで、今回は他のプログラムが読んでいるかどうかの判定として「TTYかどうか」で見るようになりました。つまり、人間が読んでるときはTTYがあるだろうということですね。標準出力がTTYのときは人間がいるとみなしてこれまでと逆順、そうでなければ後方互換性の為これまで通りという挙動に変更になっています。

zsh % ruby -e 'def foo; bar; end' -e 'def bar; raise; end' -e 'foo'
        from -e:3:in `<main>'
        from -e:1:in `foo'
-e:2:in `bar': unhandled exception

zsh % ruby -e 'def foo; bar; end' -e 'def bar; raise; end' -e 'foo' 2>&1 | cat
-e:2:in `bar': unhandled exception
        from -e:1:in `foo'
        from -e:3:in `<main>'

で、この状態でしばらく運用してみた感想ですが…… ちょっとまだ移行期間中で、今のままだと面倒が増えただけかなー。とくにtest-unitとの相性がよくないですね。test-unitのような、自分で例外を捕捉した上できれいに整形して表示するようなものが間に入ってくると、バックトレースがどっち順に表示されているかが結局二種類あるので、目で見たときに面倒の種類が増えただけになっているのが現状という気がします。

[#13097] Deprecate Socket.gethostbyaddr and Socket.gethostbyname

これらの関数はもともとPOSIXに規定されていたものですが、近年の改定でPOSIXからは削除されました。なので、もうRubyもやめていいんじゃないかという提案です。

POSIXの古いAPIを使わないようにしようというのは筋が通っているので良いかと思うのですが、とはいえRubyが外に見せるAPIが低レイヤのライブラリ関数をそのまま呼ぶ必要はないということに関しては注意が必要で、gethostbyaddrという名前でその実態はgetaddrinfoで作られているとかは可能なわけです(可能だと思う)。だから、Rubyが外に見せるAPIとしてまでこれらを削除していくべきかに関しては、やや疑問という感じになっています。

[#13241] Method(s) to access Unicode properties for characters/strings

いま、たとえば /\p{hiragana}/ =~ "あ"という正規表現マッチを行うことで、文字列にひらがなが含まれているか判定することはできます。しかし、そうではなくて、何かの謎な文字列が来たときに、それに含まれてる文字が一体どういう文字かというのを、知る方法がありません。つまり既知の文字クラスを含むかを判定できるが、文字列からその含む文字クラスを得るなどということができない。

これはちょっと対称性が悪いので、今できない方の文字クラスを得る機能を付けようというのは、まあ、わからなくもない提案かと思います。ただ、Unicodeで、文字についてくるプロパティというのは、それだけじゃないわけですよ。たとえば大文字小文字の別とか、右書き左書きとか、そういうものがある。ちょっと珍しいのでいうとUnicodeのどのバージョンで追加された文字かの情報とか。そういう多種多様のプロパティのうち、ひらがなだけ特別扱いする意味とは? と思うと、これは、あんまりなさそうなんですよね。

なので、やるとすればUnicodeのプロパティを取得するようなAPI、ということになるかと思うのですが。でも、それって、やるとすればUnicodeのプロパティのテーブルを全持ちする必要があるってことですよね…対称性が、っていう理由で入れるにはあまりに巨大すぎるような…

どうなんでしょうね、この機能誰が使うんでしょうか。

[#13077] [PATCH] introduce String#fstring method

名前が変わって String#-@ という名前になったのですけれど、今回入った新機能で、文字列のdedupができるようになりました。

問題意識としては、プログラムによっては同じ内容の文字列が大量に出現することがある。たとえばWebアプリなら、WebクライアントからWebリクエストが飛んでくるわけですけれども、これなんかは非常に高い蓋然性で"Host:"という文字列を含んでいますね。Webリクエストオブジェクトは当然これをハンドリングすると思うんですけども、ネットワーク由来の文字列だから、これは毎回全然別のメモリ領域に同じ内容のヘッダが都度生成されてくるわけです。こういうものは確かにすぐ処理が終わってゴミとして処分されるのかもしれないが、それでも既知の内容の文字列が何個も何個もメモリ上に出現しているというのは、無駄と言えるでしょう。

そこで今回から文字列に単項のマイナスが付けれるようになりました。-"foo"的な。これをすると、その文字列と同じ内容の文字列がどんどん追加されてきても、-さえついてれば同じ文字列オブジェクトが返ってくるようになります。

訂正: String#-@というメソッド自体は2.3からあったようですね。そこにdedupの機能が追加されている形でした。ごめんなさい。

[#13219] bug in Math.sqrt(n).to_i, to compute integer squareroot, new word to accurately fix it

うーん。投稿者はMath.sqrt(n).to_iという式のnの部分をどんどん大きくしていくとやがて正しくない答えが出る、というのを「バグだ」と最初主張していたわけですが。でもそれはそういうものじゃないですか。MathというのはCのlibmのラッパーで、そのすべての引数とすべての戻り値がFloat(Cでいうdouble)なわけです。だから、すごい上の方の数が正確に表現できないのは、それはそうじゃない。バグって言われても困るよ。

と思っていたら「いやsqrtにバグがあるという主張ではない、整数のsqrtを得る手段がないことがバグなのだ」と…ちょっと苦しく感じますよね。新機能が欲しいならバグとかいう強いクレームにするのは良くないという学びがあります。

さておきよく聞いていくと、巨大数の整数平方根は素数探索の方面で需要があり、たしかにこの機能はあったほうがいいということになって、Integer.sqrtというメソッドが追加されました。

[#6284] Add composition for procs

関数合成を行いたいという、よくあるといえばよくある要望なのですけれども。

ただ、関数合成といったときに、たとえば(f ∘ g)(x)という表記がf(g(x))の意味になる流儀とg(f(x))になる流儀があるというのが指摘されているわけですね。そこで、Haskellなどでいうとf (g x)f . gとpoint-freeで書けると便利というのはわかる。けどRubyの場合はそうじゃなくて、いわゆる流れるようなインターフェースっていうんですか、x.g.f()っていう書き方がf(g(x))に相当する何かなわけじゃないですか。なので、Haskellなどとは向きが逆になるんじゃないのか。このあたりのコンセンサスが求められています。まあ、「どうせ普通のRubyプログラマはこんな機能使わないし、Haskellかぶれが使いやすいようにしとけばいいじゃん」というのも見識といえば見識かもしれませんが…

それとどういう文法を入れるかにも議論があって、もともとはf << gが提案されていますが、他の人たちはf * gが好きらしいなどというところも揺れていますね。

[#13137] Hash Shorthand

ES6のオブジェクトみたいに{foo, bar}って書いたら{foo: foo, bar: bar}の意味になってほしい、という提案だったのですが、べつに読みやすくならないですね。の一言であえなくリジェクトされてしまいました。

[#4532] [PATCH] add IO#pread and IO#pwrite methods

一方こちらは新たに入った機能ですが、IOにpread/pwriteが追加になりました。これらのメソッドはマルチスレッドから同時に同じファイルを読み書きする場合に、ファイルの読み書き位地を変更しません。読み書きの順番に依存してしまうとマルチスレッドで振る舞いがよくわからなくなるので、そうならないようにしてあるわけですね。

このメソッドは低レイヤーのメソッドなので、単品で便利という感じではないかもしれませんが、たとえばDBの実装などで便利に使えるはずです。

[#12650] Use UTF-8 encoding for ENV on Windows

Windowsの場合で環境変数をUTF-8にしてほしいという要望が来ています。なお現状はいわゆるOEMコードページと呼称されるやつでとれてくる。

Windowsの場合、Rubyのことはちょっとさておくとすると、環境変数自体プロセス間ではいわゆるワイド文字で表現あるいはやりとりされているはずという理解でいますので、これをRuby側でどのようにマッピングして見せていくかという問題だけではあるんだろうと思います。

すでに古くから環境変数はCP932だという前提で書かれているスクリプトが壊れるのはたしかに困るので、デフォルトがいきなりUTF-8に変わるのは無理だと思います。しかしながらUTF-8が欲しいときにchcp 65001すればいいかというと、これは大変残念ながら不幸しか産んでいないという現状も直視する必要があると思う。

要はUTF-8モード的なものがあればいいんじゃないでしょうか。もっというとプロセス外から文字列を読み込むときにUTF-8に変換するモードがあっていいんじゃないでしょうか。もっというとそれってdefault internal encodingじゃないんでしょうか。要は環境変数がdefault internal encodingに反応すればいいと思うんですけれども、それって難しいんでしょうか。

[#13329] Creating a German ruby mailinglist on ruby-lang.org?

ドイツ語のMLが欲しい、というリクエストが来ています。

それに対して、フランス語のMLというのが実はあるのだが、これまで一度も誰もメールを送ったことがないという点が指摘されており、作っても使われないんじゃないか? という懸念が示されています。

が、とはいえ、こうしてリクエストがあるからには利用者がいることは間違いないので、まあ作ってもいいかという判断になったようです。あとはコミュニティがどう育てていくかの問題ですね。

[#12589] VM performance improvement proposal

前も紹介したかと思うのですが、VMのインストラクションセットを更新して高速化しようというプロジェクト(卜部がやってるのじゃない方)です。実装が公開され、誰でも手元で試せるようになりました。

今回のインストラクションセットの特徴はレジスタベースである点で、これまでのVMでは引数の受け渡しなどで都度スタックに積んでいた値をレジスタでとりまわすことにして、メモリ転送量を抑えることによる高速化が見込まれています。

とはいえ、マイクロベンチマークでは2倍(100% improvement)程度の高速化を見ているそうですが、Rubyにおいては多くの場合、VMインストラクションの実行よりもメソッド呼び出しとか他のところで時間を浪費する傾向にあり、そのため、ベンチマークの規模が大きくなると効果は逓減していくとのこと。まあさもありなん。

そこでやはり作者としてはJITする方向に向かいたいようですね。公開されたgithubのレポジトリでは今後の野望みたいのが語られていますが、どうせみんなCコンパイラ持ってるんだしCのコード吐いてコンパイラにコンパイルさせればいいじゃん、という方針のようです。なかなか…

気宇壮大な計画もさることながら、現状でも(速さに改善の余地ありとはいえ)きちんと動くVMが生成されているというのは実装力の証明ではあって、今後どのように開発が行われていくのかは興味深く見守りたいです。

[#12746] class Array: alias .prepend to .unshift ?

あっ、これ入りましたね。Array#unshiftの別名としてprependArray#pushの別名としてappendが、それぞれ追加されています。

最後に

マネーフォワードでは、ruby-coreが気になって夜も眠れないエンジニアを募集しています。 ご応募お待ちしています。

【採用サイト】 ■マネーフォワード採用サイトWantedly | マネーフォワード

【プロダクト一覧】 自動家計簿・資産管理サービス『マネーフォワード』 ■WebiPhone,iPadAndroid

ビジネス向けクラウドサービス『MFクラウドシリーズ』 ■会計ソフト『MFクラウド会計』確定申告ソフト『MFクラウド確定申告』請求書管理ソフト『MFクラウド請求書』給与計算ソフト『MFクラウド給与』経費精算ソフト『MFクラウド経費』入金消込ソフト『MFクラウド消込』マイナンバー管理ソフト『MFクラウドマイナンバー』資金調達サービス『MFクラウドファイナンス』

メディア ■くらしの経済メディア『MONEY PLUS』