Blog株式会社マネーフォワード公式開発者向けブログです。技術や開発手法、イベント登壇などを発信します。サービスに関するご質問は、各サービス窓口までご連絡ください。(2016年4月)こんにちは。ruby-coreというRuby本体の開発の議論がされているメーリングリストがあります。新機能やバグ報告などがだいたいここに集約されてくるので購読しておくとRubyの動きが分かります。最近興味深かったトピックを紹介します。先月長いと言われたので今回はちょっと厳選気味です。end4月といえばエイプリルフールですね。書かなくてもいいようにするパッチが投稿されていました。この投稿はだた「できるといいな」じゃなくて実際に実装してみせているので、技術的には見るものがある。endになってるわけですね。以前、Rubyのバグトラッカーにはこの種の提案のためのカテゴリjokeがわざわざ用意されていて、歴代のエイプリルフールなどが閲覧できたんですが、いつのまにかカテゴリなくなっちゃいましたね。arguments今年の4/1その2。いう変数を導入したよという提案です。20まで実装したという提案に対して、Unicodeには50まであるので中途半端ではないかというコメントが付いていて、これは提案者が負けという感じです。numこれは、もうちょっと言い方を変えると、より一般化した(10進じゃない)floorが欲しいという話です。10進じゃないfloorというのはすごく具体的な例でいうと、MySQLでcreated_atで86,400秒単位のpartitioningしている場合、とかそういうやつですよ。これは機能としては誰も反対はない気がします。提案されてる実装だと現状のfloorより10倍遅くなるというのは...このままだと厳しそうかなあ。2013以前でさほど賢くない感じでコンパイルされてしまうことが発覚、採用されずになってしまいました。C++のバージョンを上げるたびにmsvcrなんとか.dllとかvcruntimeなんとか.dllとかいうファイルを都度、しかも時にバイナリ互換性のない形で、破壊していかれるわけですよ。そんな中でも2015の時の変更は非互換がとても大きく、これまでRubyの側では対応できない状態になっていたのです。この話は月内に他のチケットで進展がありました。bracketsこの連載ではUnicode関連部分に闇ぽい現象が観測されるのはお気づきかと思いますが、実はUnicode以外にURIも結構その、あれです。いったURIをRFCに準拠した形でエスケープしてくれないのはバグ、という主張です。たしかにRFCに準拠しないのはその通りです。そもそもURIというのは構造を持った文字列で、構造のどこの部分かで使える文字が違う。「エスケープ」と一言で言っても、この部分だとこれ、みたいなルールが構造の中でそれぞれに違うわけです。エスケープする必要があるということは、そもそもの入力の文字列そのものはURIとしてはぶっ壊れてる(ぶっ壊れてるからこそエスケープする必要がある)わけですよね。文字列の中に構造を見つけることができない。できないのに構造がないとエスケープできない。これは詰んでるわけです。URIを「エスケープ」するという発想そのものが実は無理筋なのです。URI.escapeは公式見解としてobsoletedです。いう疑問が湧いてくるのは人情というものですよね。やってみると、案外どのブラウザもエスケープとかしない...つまり、Rubyの今の挙動は実情としてはブラウザと一緒なんじゃないの、という。RFCとはなんだったのか。疑問がふつふつと湧いてくるわけですね。Groupに「どーなってんの」と報告されています。続きはWHATWGで進行することと思います。heap内部構造に大きな変更を入れる提案です。いま、メモリの中でオブジェクトが16KBのかたまりでmalloc(正確にはposix_memalign(3posix))されているのですが。これは逆に言うと、確保した16KBが全部GCされるまでシステムに戻されないということでもあります。昔はもっと大きくて3MBとかだったわけですが、それだと大きすぎてなかなかメモリが解放されないということがあり、16KBというかなり小さいサイズに小分けにされた経緯があるのですが、今度は小分けの領域を管理するコストが結構馬鹿にならないよねという問題意識があります。この提案ではそこを一気に256MBの連続したメモリアドレスをmmapすることで解決しようとしています。mmapのいいところは一発で確保したアドレス空間を小分けにOSに返していくことができるという点で、これはmallocがfreeと必ず1対1で対応している必要があるのとは違う特徴です。このため、小分けの領域を管理するコスト、とかは削減できる一方で、なかなかメモリ返せない問題は4KB単位でちょっとでも空いたらすぐOSに返すことができる、一挙両得という提案になっています。明らかな問題として256MBもメモリ確保できるのかというのが常にはそうと限らないわけで、そのへんどうするのか未解決です。months「Timeがロシア語の月名に対応してません」「してませんね。いう定数参照式はFooの継承関係を遡ることもあるため、ずっと見つからないと最終的にObject::Barまで遡って、これはようするにトップレベル定数::Barなわけですね。何が嬉しいの?という議論をしたところ、とりあえずこれはトップレベル定数までは遡らないようにしようという話になりました。インスタンス変数へのアクセスを高速化したよというパッチです。これですが、そもそもRubyのインスタンス変数はいまの実装だと、オブジェクトの中に配列のようにパックされて詰まっています(中とも限らないがまあ配列ではある)。一方で、プログラム上は当然、変数名でアクセスするわけですから、名前から配列のインデックスに変換する解釈系が必要になっているわけです。ちなみにRubyのインスタンス変数というものは実行中にどんどん増えたりする(減るのはないけど)ため、静的な変換エンジンなどというものはありえません。いえ常識的に使ってればインスタンス変数なんざそうどんどん増えていったりしないわけでして、その解釈を一発やったらあとでまた使う時用に取っとこうよ、という発想はまあ自然かと思います。処理中にインラインでキャッシュする仕組みがあって、それ自体は実装済みです。この提案は、今のキャッシュ機構に問題があって、本来ならすでに取得できているはずのキャッシュをうまく見れてないんじゃないかという点の修正です。ある程度大きなメソッドになってくると、同じメソッド内で同じインスタンス変数に複数回触りに行くことがありえるのですが、そういう場合のキャッシュを(これまでなってなかったけど)一つにまとめた、ということのようです。number弱視者対応をどうするか問題。ソースコードの横幅を、いまどき80文字とかないでしょ、とばかりに横に長いコードを書いていた人に対して、自分は目が弱くて横にあんまり長いと辛いんだ、という反論が来ているところです。辛い人と辛くない人がいるなら辛い人が辛くなくなるようにするのが基本的には良いことだと思います。(CVE-2014-1266)がある程度には微妙な領域なので、これはやや慎重になるのもやむをえないところです。個人的な意見ですが、方向としては横幅の制限を入れつつ、無理のある改行にならないようにしていくといった折り合いがつくといいかなと思っています。firstSecureRandomという標準添付ライブラリがあって、だいたいの場合でOpenSSLを呼ぶようになっているのですが。いうデバイスを読もうと試みる(こともある)ように現在はなっています。この部分に問題があって(という主張で)、ユーザーランドの乱数生成器よりはカーネルで乱数作ったほうがエントロピーをじかに吸い出せるぶん安全(暗号的な意味で)であり、したがって乱数生成は常にurandomを使うべきで、OpenSSLよりも先にurandomを試して、なければOpenSSLにフォールバックすべきというふうに主張されているのです。ために非常に高品質なごく少量の種を提供するものであって、その読み出しは非常に経済的になされる必要がある」と、たいへんに強い口調で書いてあるわけです。実際には、Linuxの実装を読む限りにおいては、そんな制限はなくて、理解が正しければエントロピーが読んでる途中で枯渇してもちゃんとセキュアな感じのバイト列が返って来そうに読めるんですが。問題はそういうふうに見えるからといって、実際にmanに「やめなさい」と書いてある行為に及んでいいのか、というところで。現在の開発側の見解としては、本当にそういうのOKという意図があるならドキュメントの更新を待ってもいいのではないかということ、スレッドで騒いでる人達の見解としてはurandomには実際に問題がない以上urandomを使うべきということ、見事に平行線で、たぶんお互いに「話が通じない」と思っていて、やや険悪な雰囲気になっています。updates誰か頼む)、ひょっとしたらそもそもの状況が数年後にはドラスティックに変わっているかもしれませんね。Studioでの)autotoolsのサポートに非常にポジティブな反応を得たとのこと。nmakeをMITライセンスか何かで公開するかも、とも書いてあります。2016の前だったため、「/bin/shがないとconfigureは動かないのでは?」という素朴な疑問は当然生じていたわけですが、今から考えるとそのへんは回避されるのかなー本気かもなーという感じです。いずれにせよ、現状まだなにも確かなことは言えませんが、今後の動きは要注目ですね。model前回も紹介したこの件は引き続き議論が進んでいます。投稿しているのが全員並列プログラミングの専門家で、自分はそうではないため、かなり勘違いをしている可能性もあるんですが、おおまかな論点としては、提案者は並列実行のための新たな抽象化をRubyに入れたいモチベーションがあるようですね。そのような実装をするにはshared-everythingで厳密なメモリモデルが定義されていなければならないという話になるのはそうだろうと思いました。「このメモリモデルは専門家が使うためのものであって一般の読み物としては適さないだろう」と言ってます。いえ厳密なメモリモデルを実装するというのがそもそもあからさまにとても難しいため、定義するのはさておき可能かという面で疑問が提示されていること、及び「新たな抽象化」っていうのが現在の(難しいなりにそれなりに知見がある)スレッドを使ったやつと比べてどのくらい困難な話なのかに関して、まったく知見がなくて、本当に現実的にあり得るのかという疑問が提示されているように読めます。一家言ある人はそれぞれの意見を表明しあった感じでしょうか。いう結論になるのかわかりませんが、大きな方向性を決める話だと思うので注目していきたいです。WindowsWindows系の環境で存在するファイルに向けてopenすると、そのファイルのモードが変わってしまうことがある、という指摘です。MSVCRTの実装しているopenにおいて、書き込みモードで開きつつも書き込みビットを落としているというなかなかレアなケースでは、関数呼び出しは成功してファイルに書き込めるディスクリプタが返ってくるけど、モード自体は書き込み禁止に変更されてしまって、次回以降は書けなくなるという話ですね。それはそうなんですが、問題になっているのは「それって禁止されてないよね」という話で。POSIXのopenの仕様を読む限りにおいてはopenに第三引数をつけて呼んだ時にその引数を尊重すべきか無視すべきかあまり決まってないのですよ。ファイルが存在しなかった時にO_CREATはモードを見ると書いてあるけど、ファイルが存在した時にモード変えちゃいかんとか書いてないわけです。ファイルのオープンのような操作はランタイム依存がどうしても発生する箇所で、MSVCRTがそう作ってある以上はしょうがない、回避不能だし処理系依存というしかないということになったようです。Studioでコンパイル(正確にはリンク)できなくなってしまっていたわけですが、そもそもMSVCRTの何がそんなに問題だったかというと、IOを統一的に扱う部分なわけです。Ruby(に限らずだいたいどこでもそうだと思うんですが)ではIO多重化ということをやっています。これは、なんでかというと、そういうことをしないと読み込めないファイルを読んだ時にブロックしてしまうし書き込めないファイルに書こうとした時にブロックしてしまうからで、ブロックするのはたいへん困って、そういう操作をキャンセルできるようになってほしい。ブロックしそうな操作というものはブロックしないことが確実になるまで実際の操作を行わないということが行われているわけです。いうブロックしそうな操作というのはUnix系のOSでは(ちょっと例外あるけど)おおむねの場合でファイルディスクリプタとして抽象化されているため、fdを統一的に扱えればそれでだいたい事足りるんですが、残念なことに歴史的な経緯からWindowsではソケットに対するIOがfd経由じゃないんですな。統一的に扱いづらいのです。Windowsでは普通はどうするかというと最近はCancelIoExというやつがあって、IOを発行した後からキャンセルするということが可能になっています。残念ながらこいつは割と最近(Vista以降)に実装されたものなので、もっと古いXPとかが今ほど積極的に魔女狩りにあっていなかった時代には使いづらかった。そこをなんとかするために過去のRubyではソケットを開いた時に一緒に"NUL"をCreateFileしておいて、このHANDLEからたどれる構造体の中でソケットのディスクリプタを無理やり上書きするという行為に及んでいました(もう少し詳細な解説)。そりゃあランタイムが変わると動かなくなるよねという感じですよね。Connectに問い合わせ済みなのですが、先方からは「俺達が用意したAPIだけ使ってりゃ問題ないよ。捨てなさい」みたいな「ですよねー」としか言いようがない返答が返ってきており、まあ、どうにもならんなという感じです。しょうがないのでこの件はDLLを開いて、_isattyのちょっと後ろの辺に対象の構造体がいるはずだ!とmemcmpで検索して発見するという、なかなかひどいリバースエンジニアリングで解決されました。Git-styleChangeLogを捨てようという提案です。RubyではChangeLogというファイルが伝統的にメンテナンスされてきていました。これはまだgitやsvnはおろかcvsすら使ってなかった時代からの伝統で、いろいろなバージョン管理システムを渡り歩いた中で守られてきた「いつ何をやったかリスト」です。...という説明をしなければならないあたりに時代の流れを感じるわけですが、昔はどのプロジェクトでもやってたんですよ。最近も続けているのは少ない。なんでかというとこのファイルは1コミットごとに毎回編集されることからも分かる通り、ものすごい勢いでマージコンフリクトするんですね。ChangeLogそのものはコミットの本質ではない部分なのに、そこでコンフリクトするからマージできないというのはストレスがたまる行為です。それと、指摘されているのは、ChangeLogは「何月何日、今日はこのファイルをいじった」みたいな日記形式になっているわけですが(Logとはそもそも日記のことである)、これが夏休みの絵日記みたいな中身のない記述を促進しているのではないか、記録されるべきなのは何をしたかではなくてその背後にある意図なのではないか、という点で、その部分でChangeLogは弱いというふうに主張されています。機能的な面でChangeLog相当のものをsvnのコミットログから生成することは可能なので、ChangeLogを手で書く必要はないよねという意見に反対の人はいないようです。ChangeLogの形式で一覧するのに慣れている人もいるので、移行パスをどのようにするかが問題なのではと思います。1.1.0で多くの新機能というか非互換が入るんですね。これをセットするとたとえば短すぎる鍵を使えなくなるとか、古いバージョンのTLSが拒否されるようになるとか、そういうのが入るらしいです。これまで「おすすめ」と言われながらもなぜかデフォルトに入ってなかった「安全な設定」がとりあえず提供されるようになったと理解しています。いい話なんじゃないでしょうか。loggedRubyはマルチスレッドプログラムが書けるのですが、例外機構もあります。そこで、スレッドの中から例外が上がってきたらどうなるのかという問題があります。どこか他のスレッドから上がってきた例外でメインスレッドが停止してしまうように設定すると、ようするに本当にコントロール不可能な任意のタイミングでメインスレッドが横から止められてしまうことになって、これは基本的には安全なプログラミングというものがほぼ不可能になってしまいます。普段はそういうことはしません。逆に、スレッドの中でいつのまにか例外が一番上まで突き抜けてて、スレッドの処理が止まってしまっているという時に、それが他から非破壊的に観測できずに、「なんかよくわからんけど、動いてなさそうなスレッド」がいつのまにかできてしまうというのも困った挙動です。いうわけでとりあえず観測できないのは困るから例外が出たことをなにかに出力してくれという提案になっています。このニーズの部分に反対する人はあまりいません。いえたとえばログを出力するにしてもIOというのはようするに副作用ですから、たとえばそのログ出力のせいでIOが詰まったりしちゃったらメインスレッドにも影響はあるわけです。出力しつつも完全に影響を排除するというのも難しい。何年も議論が続いていて、今のところはスレッド単位で例外のことをなにか吐くかどうか制御できるようにしよう、という提案になっています。それをデフォルトで有効にするかどうかがまだ決まっていません。unicode多くのRubyユーザーがblank?というメソッドを使ったことがあると思うのですが、あれはライブラリのメソッドで、本体に含まれているわけではありません。それを本体に入れて欲しいという提案です。同様の提案は以前にもなんども行われなんどもリジェクトされてきましたが、今回新しいのは対象をStringに限っていてスコープを狭めている(==着地点が明確で議論が発散しづらい)こと、それから議論の中で「String#blank?がなくて困ってるケースが、ほらこんなにあるじゃないですか」とばかりに実在のコードを示してきているところです。その示しているユースケースが本当にblank?で解決するのかという点に議論があるようですが、ともあれこれまでとは一線を画す感じで議論が建設的に進行しているので、ひょっとしたらこれは入るかもなと感じさせてくれます。最後にマネーフォワードでは、ruby-coreが気になって夜も眠れないエンジニアを募集しています。ご応募お待ちしています。(2017年1月)こんにちは。最近のPython-devが始まりましたね。(2016年6月)こんにちは。読者になるこのブログについてはてなブログをはじめよう!moneyforwardDevさんは、はてなブログを使っています。ブログを報告する引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。