In Ruby, what do Method#arity and Method#parameters report for a method with optional, splat and keyword parameters?
answer
- fixed count or -n-1
- keywords count as one argument
- :req, :opt, :rest
- :keyreq, :key, :keyrest, :block
- procs report :opt; lambda: true
basics
~20 sMethod#arity returns the required count when it is fixed, otherwise -n-1 where n counts required arguments; keywords count as one argument. Method#parameters lists each parameter as [kind, name], with kinds such as :req, :opt, :rest, :keyreq, :key, :keyrest and :block.
solid answer
~40 s`arity` returns a non-negative count when a method takes a fixed number of arguments and `-n-1` when the number varies, where `n` is the number of required ones; all keywords together count as one extra argument, required if any keyword is required. So `def f(a, b = 1)` has arity `-2`, `def g(id, name:, **opts)` has arity `2`, and C methods with a variable count report `-1`. `parameters` is more precise: it returns `[kind, name]` pairs in declaration order, for example `[[:req, :row], [:opt, :width], [:rest, :extra], [:keyreq, :sep], [:key, :align], [:keyrest, :opts], [:block, :block]]`. For a non-lambda proc, `Proc#parameters` reports required-looking parameters as `:opt`; `parameters(lambda: true)` reports them as a lambda would.
code
ruby · 12 linesdef format_row(row, width = 12, *extra, sep:, align: :left, **opts, &block)
end
m = method(:format_row)
m.arity # => -3
m.parameters
# => [[:req, :row], [:opt, :width], [:rest, :extra], [:keyreq, :sep],
# [:key, :align], [:keyrest, :opts], [:block, :block]]
proc { |x, y| }.parameters # => [[:opt, :x], [:opt, :y]]
proc { |x, y| }.parameters(lambda: true) # => [[:req, :x], [:req, :y]]
"cat".method(:count).arity # => -1go deeper
Recall that arity is a count of arguments and that a negative number means the count can vary.
Explain the -n-1 rule, the single keyword group and the parameters kinds, and why plain procs report :opt.
Use parameters rather than arity when adapting to callables, and know that C methods report -1 and may omit names.
Judge whether an API should adapt to a callable's signature at all, or document one calling convention and fail loudly.
## Two ways to ask a method about its parameters A `Method`, an `UnboundMethod` and a `Proc` can all describe the parameters they accept: - **`arity`** returns a single Integer, a compact summary. - **`parameters`** returns an Array of `[kind, name]` pairs, one per parameter, in declaration order. Libraries use them to adapt to the callables they are given, for example to decide whether a formatter wants one argument or two. ## How arity is computed The rules from the `Method#arity` documentation: 1. A method that takes a **fixed** number of arguments returns that number: `def four(a, b)` gives `2`. 2. A method that takes a **variable** number returns `-n-1`, where `n` is the number of required arguments: `def five(a, b, *c)` gives `-3`. 3. **Keyword arguments count as one extra argument**, which is required if any keyword is required and optional otherwise. 4. A `&block` parameter does not count. 5. Methods written in C that take a variable number of arguments return `-1`. Worked examples: | Definition | `arity` | Why | |---|---|---| | `def f(a, b = 1)` | `-2` | one required, one optional | | `def g(id, name:, **opts)` | `2` | `id` plus the required keyword group | | `def h(x:, y: 0)` | `1` | the keyword group is required because `x:` is | | `def k(a, x: 0)` | `-2` | the keyword group is optional | | `def m(*args)` | `-1` | nothing required | ## What parameters returns | Kind | Declared as | |---|---| | `:req` | required positional `a` | | `:opt` | optional positional `b = 1` | | `:rest` | splat `*args` | | `:keyreq` | required keyword `name:` | | `:key` | optional keyword `align: :left` | | `:keyrest` | double splat `**opts` | | `:nokey` | `**nil`, no keywords accepted | | `:block` | block parameter `&block` | For `def format_row(row, width = 12, *extra, sep:, align: :left, **opts, &block)`, `method(:format_row).parameters` returns `[[:req, :row], [:opt, :width], [:rest, :extra], [:keyreq, :sep], [:key, :align], [:keyrest, :opts], [:block, :block]]`, and `arity` is `-3`: `row` and the required keyword group make two required arguments, and the optional ones make the count variable. ## Procs are different - A **non-lambda proc** does not require its arguments, so `Proc#parameters` reports `proc { |x, y| }` as `[[:opt, :x], [:opt, :y]]`. - A **lambda** reports `[[:req, :x], [:req, :y]]`. - Since Ruby 3.2, `Proc#parameters(lambda: true)` reports a proc's parameters as if it were a lambda, and `lambda: false` does the reverse. - `Proc#arity` has its own twist: a non-lambda proc with only optional positional parameters returns the required count, so `proc { |a = 0| }.arity` is `0` while `lambda { |a = 0| }.arity` is `-1`. ## The same answers from related objects - `UnboundMethod#arity` and `UnboundMethod#parameters` give the same results without a receiver, so `PriceSheet.instance_method(:format_row).parameters` works before any instance exists. - `method(:f).to_proc.arity` matches `method(:f).arity`, because the lambda made by `Method#to_proc` keeps the method's parameter rules. ## Using them well - Prefer **`parameters`** when deciding how to call something; `arity` merges required keywords and positionals into one number. - Check `arity` for friendly error messages, such as "formatter must take one argument". - A method implemented in C reports `-1` for variable arguments and may report parameters without names, so do not rely on names for core methods.
- Why is arity 2 for def g(id, name:, **opts) even though it has three parameters?All keyword parameters, including `**opts`, count as a single extra argument, required because `name:` is required. Add `id` and the count is two fixed arguments. A double splat alone does not make the count variable, so the result is `2`, not `-3`.
- How would a report generator use parameters to accept formatters of one or two arguments?Count the entries of kind `:req` in `formatter.parameters` (or `parameters(lambda: true)` for plain procs): with one, call `formatter.call(row)`; with two, call `formatter.call(row, index)`. Falling back to `arity` works for simple cases but blurs keywords into the count.
saying these in an interview costs you the question
- arity counts every parameter, including optional ones
- A negative arity means the method takes no arguments
- Each keyword parameter adds one to arity
- parameters reports a plain proc's |x, y| as :req
- A &block parameter makes arity negative