From: "jeremyevans0 (Jeremy Evans) via ruby-core" Date: 2024-08-01T14:17:54+00:00 Subject: [ruby-core:118774] [Ruby master Bug#20640] Evaluation Order Issue in f(**h, &h.delete(key)) Issue #20640 has been updated by jeremyevans0 (Jeremy Evans). mame (Yusuke Endoh) wrote in #note-3: > Briefly discussed at the dev meeting, and we found more pedantic case. We would like to see how much of a performance penalty it would bring to see if it should be fixed. > > ```ruby > def f(*a, **kw) kw[:a].class end > > h = {a: 1} > foo = Object.new > foo.define_singleton_method(:to_proc) do > h.clear > proc {} > end > p f(**h, &foo) #=> expected: Integer, actual: NilClass > ``` There would likely be a significant performance penalty. Ever method call with splat and keyword splat, splat and block, or keyword splat and block, would need at least VM instructions added to check the types of the arguments, or all such calls would need to allocate when they currently do not. My understanding was that we accept that implicit conversion methods that modify other objects can cause problems, we only try to protect against expressions in the method call causing problems. ---------------------------------------- Bug #20640: Evaluation Order Issue in f(**h, &h.delete(key)) https://bugs.ruby-lang.org/issues/20640#change-109328 * Author: jeremyevans0 (Jeremy Evans) * Status: Open * Assignee: jeremyevans0 (Jeremy Evans) * Backport: 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- Since Ruby 3.0, there is an evaluation order issue when passing a single keyword splat and a block pass expression that modifies the keyword splat: ```ruby def f(*a, **kw) kw[:a].class end h = {a: ->{}} f(**h, &h.delete(:a)) # Ruby 2.0 - 2.7: Proc # Ruby 3.0 - 3.4: NilClass ``` For single keyword splats followed by positional argument splats, this has been an issue since 3.3: ```ruby def f(*a, **kw) kw[:a].class end h = {a: ->{}} a = [] f(*a, **h, &h.delete(:a)) # Ruby 2.0 - 3.2: Proc # Ruby 3.3 - 3.4: NilClass ``` Ruby handles these issues for positional splats, duplicating the splatted array before evaluating post, keyword, or block argument expressions: ```ruby f(*a, a.pop) # post argument f(*a, **a.pop) # keyword splat argument f(*a, a: a.pop) # keyword argument f(*a, &a.pop) # block argument ``` So it should handle the case for a keyword splat that could potentially be modified by block argument expression. I'll submit a pull request shortly to fix this issue. -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/