Project

General

Profile

Actions

Bug #19280

closed

Wrong error message about arity of Data::define.new

Added by kyanagi (Kouhei Yanagita) over 1 year ago. Updated over 1 year ago.

Status:
Closed
Assignee:
-
Target version:
-
ruby -v:
ruby 3.3.0dev (2022-12-28T16:43:05Z master cada537040) [x86_64-linux]
[ruby-core:111491]

Description

$ ~/work/r/bin/ruby -e 'Data.define(:a, :b).new(1, 2, 3)'
-e:1:in `new': wrong number of arguments (given 3, expected 0..2) (ArgumentError)

Data.define(:a, :b).new(1, 2, 3)
                        ^^^^^^^
        from -e:1:in `<main>'

On this message, "expected 2" is appropriate because fewer arguments are not allowed.

$ ~/work/r/bin/ruby -e 'Data.define(:a, :b).new(1)'
-e:1:in `initialize': missing keyword: :b (ArgumentError)

Data.define(:a, :b).new(1)
                        ^
        from -e:1:in `new'
        from -e:1:in `<main>'

Related issues 1 (0 open1 closed)

Related to Ruby master - Bug #19301: Fix Data class to report keyrest instead of rest parametersRejectedActions

Updated by zverok (Victor Shepelev) over 1 year ago

  • Status changed from Open to Closed

The report about arity is correct.

Data decouples .new and #initialize this way:

  • .new accepts positional and keyword args, and converts positional to keyword, and passes them to #initialize
  • #initialize accepts only keyword arguments, and is easy to redefine for custom processing; the default implementation has all keyword arguments mandatory.

If .new method would be implemented in Ruby, for Data.define(:a, :b) it'll look this way:

KEYS = [:a, :b]

def self.new(*args, **kwargs)
  # raise if both args and kwargs provided

  # handle args
  if args.any?
    raise ArgumentError if args.size > KEYS.size 
    kwargs = args.zip(KEYS).to_h { |value, name| [name, value] }
  end

  allocate.initialize(**kwargs)
end

It other words:

  • for .new, any number of positional args is correct, as long as it has names for them
  • they are converted to keyword args, and passed to initialize
  • ...which will raise if something is missing in the default implementation, but this implementation can be redefined without .new thinking about it

Consider this:

Data.define(:a, :b) do
  def initialize(a:, b: 0) = super
end.new(1) #=> #<data  a=1, b=0>

Or even this:

Data.define(:a, :b) do
  def initialize(a: 0, b: 0) = super
end.new #=> #<data  a=0, b=0>

...so, yeah, for new, the message "it expects 0 to 2 args" corresponds to reality.

Actions #2

Updated by zverok (Victor Shepelev) over 1 year ago

  • Related to Bug #19301: Fix Data class to report keyrest instead of rest parameters added
Actions

Also available in: Atom PDF

Like0
Like0Like0