Money Forward Developers Blog

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

20230215130734

最近のruby-core (2016年2月)

こんにちは。卜部です。

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

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

最近興味深かったトピックを紹介します。  

[#12039] Fixnum#infinite?/Bignum#infinite or Numeric#infinte, consistent with Float#infinite? and BigDecimal#infinite?

FloatBigDecimal には #infinite? メソッドがあるのに FixnumBignum には存在しないので困る/欲しい、という提案です。これはあると便利ですね。

[#12040][Win32] File.stat fails on a mounted volume

Windowsにもマウントポイントという概念が(実は)あるわけですが、マウントポイントの名前が x...y みたいなへんな名前になってるときにstat取れないよ、というバグ。

コミッターが登録しているバグですので、どちらかというと備忘に近くはあります。が、内容は興味深いですね。

[#11678] ability to comment out methods in a multi-line method chain without needing a new line escape

このチケットは本文が

a = b
    .meth1
    #.meth2
    .meth3

としか書いてないけど、何が欲しいか非常に明確なのでナイスです。気持ちは分かる。

なお重複エントリでcloseされてしまっているので、この機能が欲しい人は重複先の [#7639] で議論してください。

[#12044] net/ftp.rb: add NullSocket#closed? to fix closing not yet opened connection

これはだれも反応してないように見えるけど実際は r53810 で修正されているから、BTSが同期してないだけだな。

[#9817] The extconf.rb for OpenSSL assumes MingW

何年も続いてる長いチケット。ここでいうopensslというのはrubyで標準でついてくるopensslバインディングのことですけれども、それを作るときにMinGWかそうじゃないかでリンクするライブラリが違う(これはどうやらそうらしい)、というのが問題ではないか?(問題だというのが投稿者の主張)、いやそもそもOpenSSLでGDIってなんでやねん、そのOpenSSLどこからツモってきたんだよ?(といのは他の人達の意見)、というスレッド。

[#11868] Proposal for RubyVM::InstructionSequence.compile to return an object containing the syntax error information currently written to STDERR

これはISeqというかparse.y案件の気がするんですけども、いずれにせよ今、syntax errorになったときに詳細な情報がSTDERRに吐かれているのを、そうじゃなくてコンパイル結果として(rubyレベルで)受け取りたいという要望かと。

[#11930] Segmentation Fault in gc_mark_ptr in 2.3.0p0

これ辛いやつ。GCの中でSEGVるというのはGCよりも前にすでにオブジェクトがreclaimされちゃってる系の場合が大半、今回もバックトレースによると

(gdb) p *proc
$1 = {block = {self = 0, ep = 0x16ef9b0, iseq = 0xd010c, proc = 17195200}, safe_level = 0 '\000', is_from_method = 0 '\000', is_lambda = 0 '\000'}

なので、 self = 0 はあきらかにぬるぽですね。SEGVしている箇所を調査してもだめで、まだ使ってるのにsweepしてるやつを見つける必要があります。

[#12047] Set#=== (aliased to include?)

Set===があるとwhenに並べるときに便利じゃない? という提案だが、それより*で開いた方が効率的なんじゃないの、という返しがあって、それに反論がない(イマココ)、という現状ですね。もし自分が反論しないといけないなら空間計算量の方面から攻めるかな。で、それにさらに返すとしたらsplatをiseqレベルで最適化すればいいんじゃないの(opt_plusみたいに)、という返しにするかなあ。

[#4044] Regex matching errors when using \W character class and /i option

5年以上前の1.9時代から続いているひっじょーに長い議論で、正直まだ続いててビビったんですけど、これは何かというと、 /[\W]/i という正規表現がなぜか "S" にマッチするよね、という、たしかにちょっとおかしい気がする現象なわけですけども、実は少なくともバグが報告された当時はそういう仕様っぽい感じになっていて、なぜかというと

  • Rubyでは \w とはすなわち [A-Za-z0-9_]のことである、という定義
  • なので\Wはその逆なわけだから[^A-Za-z0-9_]
  • ここで、Unicodeではいろいろな文字が収録されていて、例えばß(eszett, U+00DF LATIN SMALL LETTER SHARP S)などが含まれている
  • もちろんU+00DFは\Wに含まれる
  • そこで、/iなのだからignorecaseするわけだが、U+00DFのupcaseはSSであることがUnicodeの仕様に書いてある(参照 Unicode FAQ)
  • なので /[\W]/i 全体だと /[...SS...]/ みたいな感じに解釈されて、"S"にマッチする

という理路だったわけですよ。ただ、さすがにいくらなんでも字面から想定される挙動と異なりすぎて「ないわー」ってことになって、修正されました。

で、なんだけど、よくわからない修正のされかたをしていて、うまく説明できないよー、っていう議論が今は続いているかんじですね。実際だれもたぶん説明できない。ASCIIとかの概念を出してこないといけないのもUnicodeに閉じてなくてうまくいかないですしね。

[#12042] A better interface that returns a list of local variables available where the exception is raised

did_you_mean関連取りたい情報が取れない、というリクエストが何件かありました。これは、ちょっとわかりづらいんだけど、caller bindingのlocal variablesが欲しいということ? かな?

[#11443] DNS name resolution takes twice as long as it should when primary name server is unavailable

名前解決が二回起こってて遅いよ、という報告ですが、なんか再現しない? とか? 誰か再現する人いますかね

[#12052] String#encode with xml option returns wrong result

これは再現コードの読み方がトリッキーなので紹介。

p "<\0>\0".encode("utf-16le", "utf-16le", xml: :text)
#=> "\u6C26\u3B74\u2600\u7467;"

この "<\0>\0" という文字列オブジェクトには、[0x3c, 0x00, 0x3e, 0x00]の4バイトが含まれていて、(たぶん)文字列オブジェクト自身は「壊れた(invalid)UTF-8文字列」と判定しているところ、.encodeでutf-16leとみなす、つまりU+003C U+003Eだと思う、というところが前半。

で、それをさらにxml:で変換するので、本来は "&lt;&gt;"になって欲しいはずです。なんだけど、なってなくて、謎の文字列になっちゃってて、なんだろうね、というバグ報告ですね。

[#12056] kwarg is not allowed after return

要するに

return positional, key: value

みたいな書き方ができないけどなんで、という話です。でもこれはまつもとさん的にはNGで、「returnはメソッド呼び出しじゃないからメソッドとなんでも同じにするのは違う」とのこと。

[#12057] Allow methods with yield to be called without a block

yield でブロック渡ってこなかった時に例外じゃなくてPythonみたいにcoroutineにすればいいんじゃないの、という提案ですが、さらにコメントでcoroutineじゃなくて限定継続にしなよと煽りが入っていて、これは議論発散するパターンかもです。

かっこよさなんて所詮は主観だし、実利で攻めて欲しいところです。

[#12050] Should feature processing really accept any substring of the feature name?

rubyのコマンドラインオプションで全部書かなくても --disable-gem とか適当に省略していいのはバグか? という話。報告者はJRubyとの挙動の違いから報告しています(注:JRubyの中の人の一人です)。

で、省略できるのはそれはそれとして、省略しすぎて一意に定まらなくなった時にどういう風に振る舞うか決まってないんじゃないのという話になって、結局そういう時はエラーってことになったようですね。

[#12059] Array#single?, Hash#single?

Array#single?という定案に対して既存のone?じゃいかんのかと返っていて、その後返事なしという感じです。

[#11979] gcc-6 fails to optimize regcomp.c:compile_length_quantifier_node()

これは結論でいうとGCCのバグでした。GCC側の議論によると、三項演算子の最適化部分でバグがあった感じでしょうかね。

[#11547] remove top-level constant lookup

トップレベルじゃないところからトップレベルの定数が見えるのやめよう、という提案。これは確かにそうなってて便利と思ったことはあんましないし、まあやめてもいいんじゃないのという気がちょっとしますが…

まあ、まつもとさんの意見を聞かないことには、でしょうか。

[#11946] Assertion failed: (!STR_EMBED_P(shared)), function str_new_frozen, file string.c, line 1075.

こういうの典型的なんですが、バグ報告には再現方法が付いてないとだいたい「再現できないからよくわからん」で止まっちゃうんですよね。今回は奇跡的に他の人が再現コードを書いてくれたので、そこから糸口になって解決した幸運なパターンだけど、そうならないことも多いです。バグレポートには再現コードを付けて欲しいです。

[#12062] supporting CIDR in ENV["no_proxy"]

no_proxy という環境変数があるんですが、これに例えば10.0.0.0/8を突っ込もうとするとIPアドレスを全部一個一個展開して入れないといけないから、環境変数が200MB超まで肥大化してひどいのをなんとかしてほしいという提案です。

これはいいんじゃない? 何がブロッカーなんでしょう。

[#10793] Infrastructure/Release-Management: Sign releases

リリースしたtarにGPGで署名してほしいというリクエストで、それ自体はべつに悪い話じゃないと思うんですが、理由が「よそがやってるから」はさておき「SSLは信用ならんから」では弱いというかエキセントリックだよなあと思います。

今はdigestがHTTPS経由で確認できるから、実用上の脅威はないという認識でいます。

[#12034] RegExp does not respect file encoding directive

この件はタイトルとは裏腹にコメントは「readlink(2)でUTF8(等)としてはぶっ壊れた文字列が取得できてきた時にどう救済するか」の問題が議論されているので、そういう方向に一家言ある人の議論参加が望まれているところです。

[#11860] Double splat does not work on empty hash assigned via variable

キーワード引数で**{}はうまくいくのに、この{}を変数に代入するとなぜかうまくいかないのはなんだろう、というバグです。バグっぽいですね。

[#11758] Add keyword assignment syntax

キーワード引数にハッシュが渡せるんだからローカル変数にも渡せていいんじゃないかというリクエストですが、わかるんだけど、どうでしょうね。上にあった #12056 が望み薄なので return で返すのはあんまり入らなそうです。

[#12073] local variable interferes with keyword arguments

def a(b:)
  b
end
a = 1
a b: 9

が動かないのは変、なぜならこのb:がキーワード引数じゃなくてただの引数だったら動くので、というバグです。バグっぽいですね。

キーワード引数はまだ比較的コーナーケースが残ってるのかもしれませんね。

[#12046] Allow attr_reader :foo? to define instance method foo? for accessing @foo

attr_reader :foo? と書きたいという要望です。しかし @foo? という変数を作ることはできないので、やるとしたら、ただ変数にアクセスするアクセサというだけにとどまらない振る舞いにならざるをえない。その複雑さを許容できるだけの便利なユースケースが示せてないのでrejectということのようです。

[#12076] The 'ditto' operator

ditto という予約語があるとよいのでは。というリクエストですが、ちょっと提案がふんわりしすぎてて予約語を増やすほどの説得力を得られませんでした。

[#12024] Add String.buffer, for creating strings with large capacities

文字列の長さを指定して作成したいというリクエスト。これはまず「そんなこと必要か?」というレベルの疑問があって、文字列長を予約したいとかへんな最適化をするよりもシステム側で適当によさげに動けば変なマジックナンバーを埋め込むよりも良いのでは、という、もっともな指摘(デザインで解決する問題をユーザーにおしつけない)があったところ、たしかにreallocのオーバーヘッドが無視できない場合があって、長さ予約してあったほうが有意に高速に動くということがわかって、機能自体は必要性が認識されました。

で、次にAPIをどうするかというところで、7年前の同様の議論が掘り返されたりしていたのですが、結局String.newにキーワード引数増やしましょうということでまとまりました。

[#11934] A feature to drop dynamics dynamically

Rubyで動的な機能があるから遅いという前提だと、動的な機能を止めれるようになればいいのではないか? という提案ですが、JRuby+Truffleでやっているような脱最適化機構を入れれば動的機能を落とさなくてもペナルティはない、という反論があって、一旦は提案が取り下げになったようです。

[#10121] Dir.empty?

これはどうも各種のgemを検索してみると、テストの中でファイルを作ったりしている場合に、テストの後始末としてディレクトリが空かどうかを確認したいケースが結構あるらしい、というニーズ側の観測があったということと、コメントにも書いてある通りWindowsでは..とか常にあるとも限らないのでメソッドを提供しておいたほうがむしろ移植性が高い、という事情により、採用されました。

[#11999] MatchData#to_h to get a Hash from named captures

もう何年も前からRubyでは正規表現のキャプチャが$1とかだけじゃなくて名前で呼べるようになっているんですが、その一覧を取得する方法がないため、今だと難しいので、一覧をほしいというリクエストです。

もう少し具体的に言うとFluentdでformat /.../したときのキャプチャを次のフィルタに向けて突っ込みたいのでマッチをJSONに変換したいんだけど、書けないので、今だとかなり頑張っているというところをなんとかしたいらしいです。

ただto_hだとキャプチャに常に名前がついてるとも限らない点が問題になるということで、別の名前MatchData#named_capturesで採用されました。

[#12086] using: option for instance_eval etc.

いまイマイチつかいどころに欠けるrefinementsですが、instance_evalと混ぜて使えるようになるとDSLを書く用途で便利なのでは? という提案がありました。いまのところ誰からも反応ないようですが、これはたしかに便利になる可能性はあるので、動向には注目かもしれません。

[#12092] Allow Object#clone to yield cloned object before freezing

すでにfreezeされているオブジェクトをcloneするときに、中身を変えれると便利じゃないかという提案です。ユニークでよいのですが、ただ何に使うかよくわからない… 「immutable data structureと特異クラスを混ぜた時便利」的なことが書いてありますが、そうなんでしょうか? ちょっと想像できてないです。

[#11361] proposal for easy method to nil-guard for generated variable name.

インスタンス変数を動的に増やす時に||=のようなことがやりづらくて困るよ、という新機能要望ですね。それはそうなんだが提案で本当にやりたいことが実現できているのか? という返信がついているので、提案者はそのへんもうすこし反論するとか、考えるとかが求められていそうです。

[#12005] Unify Fixnum and Bignum into Integer

なんかもうBignumとかなくていいのでは? という提案。

誰も反対してませんし、たぶん移行パスとかの懸念だけ解決されればそうなりそうです。

[#12093] Eval InstructionSequence with binding

テンプレートエンジンでISeq保存しといて後から使いまわしたい、というニーズ(よくわかる)なのですが、コメントでソースコードをコンパイルする時にすでにbindingが必要と主張されているため、ひょっとしたら使いまわし無理なのかもしれません。だとしたら残念ですねえ。

[#12096] New notation for instance variables and class variables

Symbolが:"..."で作れるようにインスタンス変数が@"..."で作れていいんじゃないかという提案ですが、反論として@"#{...}""#{...}"とあまりに字面が同じすぎるのに意味がぜんぜん違うのでよくない、と言われています。個人的に付け加えるなら@"..."というのはObjCで文字列リテラルなので、混乱を招くのではないかなあと思います。

[#11262] Make more objects behave like "Functions"

これちょっとリクエストとして大きいんですが、ごく簡単に言うとProc以外のいろいろなクラスにcallメソッドを作って&で変換できるようにしようという話のようです。

まあ面白いとは思うんですが、Ruby本体を弄ってまで実施すべきかは提案からはよくわからないですね。gemでいいのでは?

[#11816] Partial safe navigation operator

いまfoo&.barはエラーにならないように動くんだけどfoo&.bar.bazはfooがないときにエラーになるので、foo&.bar&.baz&...とかずっと書いていかないといけないんだけど、これは不親切なのでは? という指摘ですが、だいたいの人は問題点は理解するものの今更挙動変えるのは非互換が問題になるから及び腰という感じでしょうか。

[#11666] IPAddr#private?

プライベートIPアドレスかどうか判定したい、という機能要望です。ただ、privateという名前だとメソッド可視性のprivateと混乱しやすいし、そもそもIPv6はどうなるんだという話が考慮漏れているので、このままでは入らないでしょう。

[#12119] next_prime for lib/prime.rb

ruby -rprime -e 'p (2**61-1).prime?' とか戻ってこないけど、この程度の桁ならMiller-Rabinでdeterministicに高速判定できるから、もっと大きな桁だったらOpenSSL::BNでもいいけど、64bit整数くらいまでは速くしましょうよ、という提案です。

悪くないと思うんですよね。要求は明確だしコードもあるし。ただprimeをどのくらい実務的に使うか? というところが自分はよくわかってないです。

[#12110] Create a method to avoid vacuous truth?

これは空配列に対する[].all? {|x| なにか式 }が常に真で返ってくるのがへん、という指摘なのですが、そもそもall?は数理の全称量化から来ているわけで、その定義からも今の振る舞いはしょうがないのかなと思います。

ただ、なんとなく議論がずれているのですが、もともとはall?の振る舞いをどうこうしたいのではなく、新たなメソッドを作りましょうという話だったような…

[#12103] ruby process hangs while executing regular expression.

正規表現が遅いのは毎度のことながら「そういう正規表現を書くのが悪い」という話に落ち着くのですが、とはいえ同じ正規表現を「perlなら実行できる」ということも、実際によくあるので、きっとperlの正規表現エンジンは最適化が頑張られているのだと思います。rubyのやつもひょっとしたら典型的な場合を救っておくと、バグレポートが減ってみんなが幸せになるのかもしれませんね。  

最後に

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

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

【プロダクト一覧】 ■家計簿アプリ・クラウド家計簿ソフト『マネーフォワード』家計簿アプリ・クラウド家計簿ソフト『マネーフォワード』 iPhone,iPad家計簿アプリ・クラウド家計簿ソフト『マネーフォワード』 Androidクラウド型会計ソフト『MFクラウド会計』クラウド型請求書管理ソフト『MFクラウド請求書』クラウド型給与計算ソフト『MFクラウド給与』経費精算システム『MFクラウド経費』消込ソフト・システム『MFクラウド消込』マイナンバー対応『MFクラウドマイナンバー』創業支援トータルサービス『MFクラウド創業支援サービス』お金に関する正しい知識やお得な情報を発信するウェブメディア『マネトク!』