Misc #19971
openConfusing arity of a Proc with implicit rest parameter
Description
I've noticed that such proc proc { |a,| }
has arity 1
:
proc { |a,| }.arity # => 1
that means only one required parameter, but the proc behaves similar to a proc with explicit rest parameter (proc { |a, *| }
) that has arity -2
:
proc { |a, *| }.arity # => -2
that means one required parameter and rest parameter.
So I am wondering whether it's intentional behaviour and what the rational is behind it.
Updated by shan (Shannon Skipper) about 1 year ago
Docs say it's intended, since #arity "returns -n-1, where n is the number of mandatory arguments, with the exception for blocks that are not lambdas and have only a finite number of optional arguments; in this latter case, returns n." A Proc in this case isn't a lambda, so it returns n
rather than -n-1
. Procs have loose arity, like blocks, unlike lambdas.
Updated by zverok (Victor Shepelev) about 1 year ago
@shan (Shannon Skipper) I don't think this documentation definition covers the case described by OP.
proc { |a,| }
is not the same as proc { |a| }
, and is semantically equivalent of proc { |a,*| }
. I think it is reasonable to expect its arity
—and, by the way, parameters
, would behave as in latter, not as in former.
I think this would be reasonable (and might be useful for metaprogramming code that checks the signature of the passed callable object):
proc { |a| a }.call([1, 2, 3]) #=> [1, 2, 3]
proc { |a| }.arity #=> 1
proc { |a| }.parameters #=> [[:opt, :a]]
proc { |a, *| a }.call([1, 2, 3]) #=> 1
proc { |a, *| }.arity #=> -2
proc { |a, *| }.parameters #=> [[:opt, :a], [:rest, :*]]
proc { |a,| a }.call([1, 2, 3]) #=> 1, like the latter
proc { |a,| }.arity #=> 1, should be -2
proc { |a,| }.parameters #=> [[:opt, :a]], should be [[:opt, :a], [:rest, :*]]
Though, experimenting a bit more with it, there is a funny edge case:
define_method(:m1, &proc { |a| })
define_method(:m2, &proc { |a, *| })
define_method(:m3, &proc { |a,| })
p method(:m1) #<Method: Object#m1(a)>
p method(:m2) #<Method: Object#m2(a, *)>
p method(:m3) #<Method: Object#m3(a)> --- like 1, not like 2
...which is probably related to reported arity/parameters.
Updated by shan (Shannon Skipper) about 1 year ago
Ah, I see. Thanks for clarifying! FWIW, lambdas don't ack the implicit rest either.
Updated by andrykonchin (Andrew Konchin) 12 months ago
- Description updated (diff)