def method(a, b='a', c, *d)
[a,b,c, d]
end
p method(1,2,3,4)
doesn't work, I don't understand why, if we remove the b parameter all works well. The syntax rules say that you can put params with default values before the splat parameter.
def method(a, b='a', c, *d)
[a,b,c, d]
end
p method(1,2,3,4)
doesn't work, I don't understand why, if we remove the b parameter all works well. The syntax rules say that you can put params with default values before the splat parameter.
Variables with defaults and a splat variable can exist and coexist as long as variables with defaults can be interpreted as the initial elements of the (one and only) splat.
As a result, these will all work:
def good(a = :a, b); [a,b]; end
def good(a = :a, *b); [a,b]; end
def good(a, b = :b, *c); [a,b,c]; end
But these won't:
def bad(*a, b = :b); [a,b]; end # default after the splat
def bad(a = :a, b, c = :c); [a,b,c]; end # parsing would need two splats
def bad(a = :a, b, *c); [a,b,c]; end # parsing would need two splats
def bad(*a, b = :b, c); [a,b,c]; end # default after the splat
(Tbh, I have no idea what implementation details prevent Ruby from accepting defaults immediately after a splat provided there is no ambiguity. But I'm guessing it's to avoid looping twice over the splat instead of a single time, i.e. performance, and that there might be additional reasons that may have something to do with the way Ruby computes a method's arity.)
Default parameters (b
) should come after positional parameters (a
, c
):
def method(a, c, b='a', *d)
[a,b,c, d]
end
There is something going on under the hood:
def method(a=7, b, *c); end
SyntaxError: (irb):25: syntax error, unexpected *
def method(a=7, b, *c); end
^
def method(*b, *c); end
SyntaxError: (irb):26: syntax error, unexpected *
def method(*b, *c); end
^
Notice that is the same error. When you place a param with a default value anywhere other than the end of the fixed parameter list, I expect that internally Ruby is using the same structure to represent that as it uses for the splat (the Ruby C API method for this is rb_scan_args
) . Therefore, you cannot have mid-position default values due to the same limitations placed on multiple splats.
AFAICS, this is not a technical limitation of the language, but an implementation detail - clever handling of defaults in non-ending positions in Ruby is re-using the data structures and logic used for splats. The splats have to be limited in that way (because two splats are ambiguous), but it is in theory possible to have a scheme that supports the defaults in your question. Probably though it is an unusual enough requirement that you won't see it done in near future. I would suggest simply moving your named optional params to just before the splat param.