今週の気になった bugs.ruby
ちょっと遅れましたが貯めてはいました。
内容は適当です。
今週と言っても今週みかけたチケットなだけでチケット自体は昔からあるやつもあります。
[Feature #15973] Let Kernel#lambda always return a lambda
lambda(&proc {}).lambda?
の戻り値がfalse
になるのでtrue
にしよう、という提案- Ruby 2.7 現在では以下のような挙動になっている
# lambda にブロックを渡す # OK: true が返る p lambda {}.lambda? # => true # lambda に lambda を渡す # OK: true が返る p lambda(&lambda {}).lambda? # => true # lambda に proc を渡す # NG: false が返る p lambda(&proc {}).lambda? # => false
- 議論は長いんですが結果的には以下のように対応することになったみたい
- Ruby 3.0 では
lambda(&b)
を呼び出すと警告が出るようにする - Ruby 3.1 以上ではエラーになるようにする
- 詳しくはこちら:https://bugs.ruby-lang.org/issues/15973#note-46
- Ruby 3.0 では
- この対応はすでに ruby-dev にて実装済み
# ruby-dev での挙動 # no warning lambda {} # warning: lambda without a literal block is deprecated; use the proc without lambda instead lambda(&lambda {}) # warning: lambda without a literal block is deprecated; use the proc without lambda instead lambda(&proc {}) # warning: lambda without a literal block is deprecated; use the proc without lambda instead lambda(&method(:puts))
[Feature #12901] Anonymous functions without scope lookup overhead
Proc
などを定義する際に『外部のスコープを参照しないこと』を明示化することでオーバーヘッドをなくしパフォーマンスが向上させるチケット- チケット自体は3年前につくられた
# 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
が動かないよね?みたいなことも言われてる
Guild/Ractor
には外部スコープを参照しないようにするProc#isolate
というメソッドがあるらしい?- レシーバをキャプチャしない場合は
UnboundMethod
に近いのでは?というコメントも
# こういう構文だとどうか plus = def->(a) = self + a plus.bind_call(1, 2) #=> 3 plus_1 = plus.bind(1) plus_1.call(11) #=> 12
[Feature #6869] Do not treat _
parameter exceptionally
def hoge(a, a) end
みたいに同名の仮引数を定義するとduplicated argument name
とエラーになる- しかし
def hoge(_, _) end
のように_
を仮引数としてつかった場合はエラーにならない _
が特別な挙動になるのはやめましょう、とう提案
# OK def hoge(_, _) end # NG: duplicated argument name def hoge(a, a) end
- チケット自体は 8年前につくられていて最近コメントされていたので読みました
_
が特別な意味を持つのがもにょるのはわかるんですがどうなんでしょうね
[Feature #16954] A new mode Warning[:deprecated] = :error
for 2.7
Warning[:deprecated] = :error
でdeprecated
な警告をエラーにするか警告にするかを制御できるようにする提案- 挙動としては以下のような感じ
-
Warning[:deprecated] = :error
, to make the warning into an error which produces a full backtrace (and stops the execution). -
Warning[:deprecated] = :debug
, to make the warning print a full backtrace (and continues the execution).
-
- このあたりがユーザ側で制御できるのはいいのではなかろうか?
- ちなみにコメントに書いてあったんですが、以下のようにすると Ruby だけで実装することもできるらしい
- warning gem というライブラリがあるぽい
- https://rubygems.org/gems/warning
require 'warning' # warning gem Warning.process do |message| if message =~ /: warning: (?:Using the last argument (?:for `.+' )?as keyword parameters is deprecated; maybe \*\* should be added to the call|Passing the keyword argument (?:for `.+' )?as the last hash parameter is deprecated|Splitting the last argument (?:for `.+' )?into positional and keyword parameters is deprecated)\n\z/ if false # :error raise message else # :debug $stderr.puts message $stderr.puts caller end else $stderr.puts message end end def a(a, b: 1); end a(b: 2) # keyword to positional def a(a=1, b: 1); end a({b: 1, 'a'=>1}) # split positional a(b: 1, 'a'=>1) # split keyword def a(b: 1); end a({b: 1}) # positional to keyword
- こういう感じでハックできるのはいろいろと捗りそう