
Issue #20218 has been updated by jeremyevans0 (Jeremy Evans). In Ruby 3.3, behavior is inconsistent: ```ruby a = Class.new do def [](*a, **kw, &b) p([a, kw, b]) 0 end alias []= [] end.new b = proc{} # Regular assignment treats keywords as positional a[1, 2, bar: 3, &b] = 4 # [[1, 2, {:bar=>3}, 4], {}, #<Proc:0x00000b17febec6e0 (irb):8>] # Operator assignment respects keywords a[1, 2, bar: 3, &b] += 4 # [[1, 2], {:bar=>3}, #<Proc:0x00000b17febec6e0 (irb):8>] # [[1, 2, 4], {:bar=>3}, #<Proc:0x00000b17febec6e0 (irb):8>] # Mass assignment crashes process a[1, 2, bar: 3, &b], _ = 4, 5 ``` Due to keyword argument separation, the regular assignment behavior for keywords should be considered incorrect. It could be changed to make it similar to operator assignment, but that would be worse in terms of backwards incompatibility, because it would silently change behavior. With the change to make it invalid syntax, at least the few Ruby users using the syntax know to update their code. You can still call the `[]` and `[]=` methods with keywords and a block, using `send`/`public_send`, in which case you can specify which arguments are positional and which are keywords. ---------------------------------------- Bug #20218: aset/masgn/op_asgn with keyword arguments https://bugs.ruby-lang.org/issues/20218#change-108372 * Author: jeremyevans0 (Jeremy Evans) * Status: Closed * Backport: 3.0: UNKNOWN, 3.1: UNKNOWN, 3.2: UNKNOWN, 3.3: UNKNOWN ---------------------------------------- I found that use of keyword arguments in multiple assignment is broken in 3.3 and master: ```ruby h = {a: 1} o = [] def o.[]=(*args, **kw) replace([args, kw]) end # This segfaults as RHS argument is not a hash o[1, a: 1], _ = [1, 2] # This passes the RHS argument as keywords to the method, treating keyword splat as positional argument o[1, **h], _ = [{b: 3}, 2] o # => [[1, {:a=>1}], {:b=>3}] ``` Before 3.3, keyword arguments were treated as positional arguments. This is similar to #19918, but for keyword arguments instead of block arguments. @matz indicated he wanted to prohibit block arguments in aset/masgn and presumably also op_asgn (making them SyntaxErrors). Can we also prohibit keyword arguments in aset/masgn/op_asgn? Note that aset treats keyword arguments as regular arguments: ```ruby o[1, a: 1] = 2 o # => [[1, {:a=>1}, 2], {}] o[1, **h] = {b: 3} o # => [[1, {:a=>2}, {:b=>3}], {}] ``` While op_asgn treats keyword arguments as keywords: ```ruby h = {a: 2} o = [] def o.[](*args, **kw) concat([:[], args, kw]) x = Object.new def x.+(v) [:x, v] end x end def o.[]=(*args, **kw) concat([:[]=, args, kw]) end o[1, a: 1] += 2 o # => [:[], [1], {:a=>1}, :[]=, [1, [:x, 2]], {:a=>1}] o.clear o[1, **h] += {b: 3} o # => [:[], [1], {:a=>2}, :[]=, [1, [:x, {:b=>3}]], {:a=>2}] ``` -- https://bugs.ruby-lang.org/