Project

General

Profile

Actions

Bug #20251

closed

Wrong ArgumentError raised for hash as last parameter before keyword aguments

Added by phillipp (Phillipp Röll) over 1 year ago. Updated over 1 year ago.

Status:
Feedback
Assignee:
-
Target version:
-
ruby -v:
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux]
[ruby-core:116650]

Description

Suppose we have the following method as part of an API client:

def post(path, params, timeout: 30)
end

The method is then called like this:

post("/persons", name: "John Doe")

This leads to an error message ArgumentError: wrong number of arguments (given 1, expected 2). I suppose the (implicit) hash is used for keyword arguments.

My expectation would be, that:

  1. the Hash (passed without the brackets, but that is not needed in other cases) would be accepted as the params argument or
  2. that an ArgumentError would be raised with the message ArgumentError: unknown keyword: :name

In my opinion, the first case should be what's happening, the second behaviour would be my expectation if that's not possible, because a hash without brackets can't be mixed without passing keyword arguments.

Either way, starting with Ruby 3.0, the behaviour makes no sense to me anymore.

Actions #1

Updated by phillipp (Phillipp Röll) over 1 year ago

  • Description updated (diff)

Updated by nobu (Nobuyoshi Nakada) over 1 year ago

  • Status changed from Open to Feedback

You need {/} to make the argument a Hash instead of a keyword argument.

post("/persons", {name: "John Doe"})

The semantics around keyword arguments has been changed at 3.0.
Ruby 2.7 or earlier worked like as you described.

Updated by phillipp (Phillipp Röll) over 1 year ago

I know and unserstand that, but still, is the raised exception not wrong? Should that not be ArgumentError: unknown keyword: :name?

Updated by jeremyevans0 (Jeremy Evans) over 1 year ago

phillipp (Phillipp Röll) wrote in #note-3:

I know and unserstand that, but still, is the raised exception not wrong? Should that not be ArgumentError: unknown keyword: :name?

Positional argument arity is checked before keyword arguments are checked. I don't think it makes sense to delay raising the error to try to find all additional possible errors. Certainly just showing unknown keyword: :name is wrong, because even if you removed the keyword argument, the call would still have a positional argument arity error.

I think your main conceptual problem is here:

the Hash (passed without the brackets, but that is not needed in other cases) would be accepted as the params argument or

This is inaccurate starting in Ruby 3. Keyword arguments are separated from positional arguments. For backwards compatibility, a method that does not accept keyword arguments will convert the keyword arguments to a hash. However, the call itself does not pass a hash, it passes keywords. See https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/ for details.

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0