Project

General

Profile

Actions

Bug #21844

open

Inconsistent ArgumentError message for Data::define.new

Bug #21844: Inconsistent ArgumentError message for Data::define.new

Added by jnchito (Junichi Ito) about 1 month ago. Updated 11 days ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 4.0.1 (2026-01-13 revision e04267a14b) +PRISM [arm64-darwin25]
[ruby-core:124594]

Description

The code below shows Data::define.new treats symbol and string keys equivalently:

C = Data.define(:a, :b)

C.new(a: 1, b: 1)
#=> #<data C a=1, b=1>

C.new('a' => 1, 'b' => 1)
#=> #<data C a=1, b=1>

But it acts differently when detecting missing keywords:

C.new(a: 1)
#=> 'Data#initialize': missing keyword: :b (ArgumentError)
C.new('a' => 1)
#=> 'Data#initialize': missing keywords: :a, :b (ArgumentError)

I feel it should work like this:

C.new('a' => 1)
#=> 'Data#initialize': missing keyword: :b (ArgumentError)

I created a PR to fix it:

https://github.com/ruby/ruby/pull/15910

Updated by nobu (Nobuyoshi Nakada) about 1 month ago Actions #1 [ruby-core:124595]

  • Backport changed from 3.2: UNKNOWN, 3.3: UNKNOWN, 3.4: UNKNOWN, 4.0: UNKNOWN to 3.2: REQUIRED, 3.3: REQUIRED, 3.4: REQUIRED, 4.0: REQUIRED

Another related issue:

Data.define(:a, :b).new(a: 0, "a" => 1)

This creates an instance of Data with b not initialized, #<data a=1, b=nil>.

Updated by jnchito (Junichi Ito) about 1 month ago 1Actions #3 [ruby-core:124600]

Is this behavior in Ruby 4.0.1 expected?

Data.define(:a, :b).new(1 => 1, a: 2)
#=> #<data a=2, b=1>

Data.define(:a, :b).new(1 => 1, b: 2)
#=> #<data a=nil, b=2>

I expected ArgumentError to be raised because 1 is an unknown keyword.

For example, the following behavior is natural for me:

def x(a:,b:);end

x(1=>1,a:2)
#=> missing keyword: :b (ArgumentError)

x(1=>1,b:2)
#=> missing keyword: :a (ArgumentError)

x(1=>1,2=>2)
#=> missing keywords: :a, :b (ArgumentError)

Updated by nobu (Nobuyoshi Nakada) about 1 month ago Actions #4

  • Status changed from Open to Closed

Applied in changeset git|c27ae8d91aadca0660070ee1eeae9598b1fe47ee.


[ruby/psych] Remove excessive check of message

The order of "unexpected" and "missing" keyword argument errors at
Data#initialize had not been defined strictly.

Bug #21844
ruby/ruby#15910

https://github.com/ruby/psych/commit/ba748d9b04

Updated by Earlopain (Earlopain _) about 1 month ago Actions #5

  • Status changed from Closed to Open

Updated by jnchito (Junichi Ito) about 1 month ago Actions #6 [ruby-core:124602]

I couldn't find the spec, but I found keywords can be index like Array:

Data.define(:a, :b).new(0 => 1, 1 => 2)
#=> #<data a=1, b=2>

Data.define(:a, :b).new(-2 => 1, -1 => 2)
#=> #<data a=1, b=2>

So the code below seems to be OK:

Data.define(:a, :b).new(1 => 1, a: 2)
#=> #<data a=2, b=1>

But the following code should raise ArgumentError(missing keyword: :a), right?

Data.define(:a, :b).new(1 => 1, b: 2)
#=> #<data a=nil, b=2>

Updated by jnchito (Junichi Ito) about 1 month ago Actions #7 [ruby-core:124603]

With this PR, Data#initialize now considers index keys when detecting missing keywords:

https://github.com/ruby/ruby/pull/15910

Updated by Eregon (Benoit Daloze) about 1 month ago · Edited Actions #8 [ruby-core:124608]

I believe we should be strict with arguments for Data.new:
Only keyword arguments with symbol keys matching the members, or an Array with the correct number of elements (same as # of members) should be accepted, everything else should be an ArgumentError.

Data.define(:a, :b).new(1 => 1, a: 2) should be an error, that seems a bug in CRuby (and already an error in TruffleRuby).
Same for Data.define(:a, :b).new(0 => 1, 1 => 2) or any non-Symbol keys.

This is necessary for sanity and be able to optimize Data.new reasonably.

I don't think any code is using such weird ways to create Data instances.

Updated by nobu (Nobuyoshi Nakada) about 1 month ago Actions #9 [ruby-core:124609]

@Eregon (Benoit Daloze) If so, should deconstruct_keys also be an error?

klass = Data.define(:x, :y)
d = klass.new(1, 2)

d.deconstruct_keys([0, 1]) #=> ?

Updated by Eregon (Benoit Daloze) about 1 month ago · Edited Actions #10 [ruby-core:124612]

Yes, I think so, I don't think anyone is using something as obscure as case data in MyData(0 => a, 1 => b) when they can just case data in MyData(a:, b:) or case data in MyData[a, b].

Updated by matz (Yukihiro Matsumoto) 11 days ago 1Actions #12 [ruby-core:124778]

OK, these are bugs (string keys, integer keys). We should fix.

Matz.

Actions

Also available in: PDF Atom