2022/01/21 今回の気になった bugs.ruby のチケット
今週は CRuby を WASI に対応する変更がマージされました。
[Feature #18462] Proposal to merge WASI based WebAssembly support
- CRuby を WASI に対応するチケット
- WASI は WebAssembly をブラウザではなくて OS で動かすための共通のプラットフォーム仕様らしい
- これを使用すると Web ブラウザだけではなくて WASI に対応していれば環境に依存せずに CRuby が動作する感じなんですかね?
- この対応は既にマージされています
- 詳しくは以下を参照
[Bug #17545] Calling dup on a subclass of Proc returns a Proc and not the subclass
Proc
を継承したクラスでdup
を呼ぶとサブクラスではなくてProc
オブジェクトが返ってくるバグ報告
class MyProc < Proc end p MyProc.new {}.dup # => #<Proc:0x00007f2a6fadd8b0 /tmp/v9WO1yb/17:4>
class MyProc < Proc def dup self.class.new(&super) end end p MyProc.new {}.dup # => #<MyProc:0x00007f0bf0b95368 /tmp/v9WO1yb/18:7>
[Bug #18487] Kernel#binding behaves differently depending on implementation language of items on the stack
- 現在のスタックフレームでない
binding
オブジェクトを取得することができるというバグ報告 - 以下のようなコードでメソッドの呼び出し元の
binding
オブジェクトを取得する事ができる
class Magic define_singleton_method :modify_caller_env!, method(:binding).to_proc >> ->(bndg) { # 呼び出し元の binding オブジェクトに対してローカル変数を設定する bndg.local_variable_set(:my_var, 42) } end my_var = 1 Magic.modify_caller_env! p my_var #=> 42
- なるほど?
Proc#>>
あたりで関数合成しているのがポイントなんですかね?
[Feature #18461] closures are capturing unused variables
- Ruby では使用されていないローカル変数もキャプチャしている
def foo a = 1 ->{} end # メソッド内で a は使用されていないが a という変数をキャプチャしている p foo.binding.local_variables # [:a]
- これを最適化しようという提案
- JavaScript エンジンの V8 だと同様の最適化をしているらしい
- しかし、Ruby の場合は
binding
を経由して外から変数を参照できたりする
def foo a = 1 [->{}, ->{}] end x, y = foo x.binding.local_variable_get(:a) # => 1 y.binding.local_variable_get(:a) # => 1 x.binding.local_variable_set(:a, 2) x.binding.local_variable_get(:a) # => 2 y.binding.local_variable_get(:a) # => 2
- 議論は盛り上がっているんですが今は結論が出ないまま止まっちゃってるぽいですね
- 最適化を行うと非互換になってしまうんですが、仮に最適化した場合どれぐらいパフォーマンスが向上するんですかね?
- 普段コードを書いている時に基本的に無駄な変数は定義しないようにしているのでそんなに効果があるかちょっと懐疑的
- 実行時に最適化するんじゃなくて Warning 出たりするぐらいで十分なんじゃないかなあ
[Feature #18438] Add Exception#additional_message
to show additional error information
- 現状
did_you_mean
やerror_highlight
などはException#message
を書き換えてエラーメッセージを変更している
begin; 1.time; rescue NoMethodError; pp $!.message; end #=> "undefined method `time' for 1:Integer\n" + # "\n" + # " 1.time\n" + # " ^^^^^\n" + # "Did you mean? times"
- これには問題があって
Exception#message
を変更するのでException#message
の戻り値をチェックするテストを中断してしまう- 実際
minitest
のテストが壊れたらしい
- 実際
- この問題を対処するために
Exception#additional_message
という新しいメソッドを追加する提案
class MyError < StandardError def message = "my error!" # エラーメッセージに追加するテキストを定義する def additional_message = "This is\nan additional\nmessage" end raise MyError
$ ./miniruby test.rb test.rb:6:in `<main>': my error! (MyError) | This is | an additional | message
- コメントでは以下のように意味が異なるメソッドを分けて定義するアプローチも提案されている
def message @message end def description(highlight: false) "#{message}\nSome extra info" end def full_message(highlight: false, order: ...) "#{description(highlight: highlight)}\n#{backtrace...}" end
- まつもとさん的には
Exception#description
の方が好みっぽいですね
[Bug #15928] Constant declaration does not conform to JIS 3017:2013
- 次のように定数を代入する時に
rhs -> expr
の順で評価が行われる
expr::C = rhs
- しかし、これは JIS 3017:2013 に準拠していないというバグ報告
- 2年以上前のチケットだったが最近修正された
- 最新版では
expr -> rhs
の順番で評価されるようになる
def expr print "expr -> " Object end def rhs print "rhs -> " end expr::Hoge = rhs # Ruby 3.1 => rhs -> expr -> # Ruby 3.2 => expr -> rhs ->
[Bug #18435] Calling protected
on ancestor method changes result of instance_methods(false)
instance_methods(false)
はレシーバのクラスオブジェクトで定義されているメソッド名のみを返す
module A def method1() end end class B include A def method2() end end p B.instance_methods(false) #=> [:method2]
- しかし、親クラスのメソッドを
protected
するとinstance_methods(false)
にも含まれてしまうというバグ報告- ちなみに親クラスの
private
メソッドをサブクラスでpublic
にすると同様の挙動になる
- ちなみに親クラスの
module A private def method1() end end class B include A public :method1 def method2() end end p B.instance_methods(false) #=> [:method2, :method1] p B.instance_method(:method1).owner #=> A
- この問題は最新版だと修正済み