【一人 bugs.ruby Advent Calendar 2020】[Feature #12901] Anonymous functions without scope lookup overhead【13日目】
一人 bugs.ruby Advent Calendar 2020 13日目の記事になります。
[Feature #12901] Anonymous functions without scope lookup overhead
Proc
などを定義する際に『外部のスコープを参照しないこと』を明示化することでオーバーヘッドをなくしパフォーマンスを向上させるチケットです。
# scope: false をキーワード引数で渡すことで『キャプチャしないこと』を明示化 Proc.new(scope: false) {|var| puts var } # これは以下のようにメソッドを定義したときと同じ意味 def anon(var) puts var end # 動作例 var = "hello" Proc.new(scope: false) { puts var }.call # => NameError: undefined local variable or method `var' for main:Object
内容がかなり難しいので適当に拾うと
* binding
や self
が絡んでくると最適化するのがむずかしい
* self
をキャプチャしない場合は puts some_expression
が動かないよね
みたいな議論がされてるぽい?です。
他には以下のように def->(a) =
という構文で UnboundMethod
みたいなもの生成するのはどうか、みたいな提案もされていました。
# plus が UnboundMethod ぽいオブジェクトになる plus = def->(a) = self + a # plus は第一引数を self として受け取り、それ以降は def で定義した仮引数で受け取る plus.bind_call(1, 2) #=> 3 plus_1 = plus.bind(1) plus_1.call(11) #=> 12
なんかこのあたりの変数スコープの話を見てると C++ のラムダ式を思い出しますね。
C++ のラムダ式は Ruby とは違い明示的にキャプチャする変数を指定するような形になっています。
auto a = 1; auto b = 2; // [] に参照する変数を指定する auto plus = [a](auto x) { // このスコープ内では a しか参照できない return a + x; };
Ruby でもこんな感じで明示化するといいんですかね?めんどくさいかなぁ。