How to set a default value for a splat argument in Ruby
Asked Answered
S

4

13

Setting a default value for a splat argument gives an error:

1.9.3-p374 :001 > def a b, *c = nil
1.9.3-p374 :002?>   end
SyntaxError: (irb):1: syntax error, unexpected '=', expecting ';' or '\n'
def a b, *c = nil
             ^
    from /Users/me/.rvm/rubies/ruby-1.9.3-p374/bin/irb:16:in `<main>'

Some variations I tried that don't work either:

1.9.3-p374 :003 > def a b, *c = []
1.9.3-p374 :005 > def a b, (*c) = nil
1.9.3-p374 :007 > def a b, (*c = [])
1.9.3-p374 :009 > def a b, (*c = [1,2,3])
1.9.3-p374 :011 > def a b, *c = [1,2,3]

I don't see an indeterminacy issue here, so it seems like it should be possible.

Related: Why non-explicit splat param plus default param is wrong syntax for method definition in Ruby 1.9?

Sememe answered 3/4, 2013 at 20:16 Comment(4)
Splat argument by default is empty arrayWengert
Yes, but what about a default argument?Sememe
Is there a reason you haven't accepted an answer yet?Strabismus
@Strabismus I was hoping that someone would address the technical reason of why Ruby doesn't allow setting default params for splats in the usual way. I did read what you said about it being a design decision.Sememe
S
6

Your attempted usage is counter the conventions around splat usage. Splats are supposed (at least in Ruby) to take up all extra (0, 1 or more) values.

If you know that you want the second value in your method arguments list to have a default value, you could take it out of the splat and list it just before the splat with a default value like this:

def a b, c=nil, *d 
  # rest of code omitted
end

EDIT: To make the answer to your question of why it doesn't work perfectly clear. It's a design decision by the language designer. Matz never intended the splat operator to work with defaults. This seems pretty sensible to me since it is intended to be used for catching an indeterminate number of variables and because the method I described reads more clearly than the possibilities you described and because all of the problems your examples solve are solvable in other ways.

Strabismus answered 3/4, 2013 at 20:26 Comment(1)
+1 This is the right way to go about this. If c is that special, promote it to its own parameter entry, and don't play games trying to extract it from the splatted variable.Retrench
H
5

You could set the default value in the method itself knowing that the default splat returns an empty array.

def test(a, *b)
  b = "default b" if b == [] # edited as per Tin Man's recommendation
  puts [a, b].inspect
end

test("Test", 1, 2)
# => ["Test", [1, 2]]
test("Test")
# => ["Test", "default b"]

In Rails, you could check for b.present? as an empty array is considered blank. Hope that helps.

Hairdo answered 3/4, 2013 at 20:28 Comment(4)
b == [] and b = "default b" is not recommended for Ruby style. Use b = "default b" if b == [].Retrench
Thanks, I incorporated your suggestion. Is there a technical reason behind this?Hairdo
It's a readability and maintenance issue. Using a boolean to join the conditional test and assignment is very much a C/Perl construct; It's terse, almost cryptic, without gaining appreciable, if any, speed. When writing in C or Perl it's expected, almost macho, to be able to write like that, but the Ruby way is to give a bit on terseness for more readability. Also, if you use and, and then add additional tests or assignments, order of precedence can bite you, which can be very hard to track down. Using && avoids the precedence problem a lot of times, but doesn't increase readability.Retrench
Thanks a lot @theTinMan for elaborating!Hairdo
B
0

A splat argument defaults to an empty array, without your having to do anything special.

def a(b, *c)
  c
end

a("foo")
#=> []
Benbena answered 3/4, 2013 at 20:23 Comment(2)
Yes, but what about a default argument besides nil?Sememe
See my answer for what to do when you want c to have a default valueStrabismus
M
0

This is very convenient:

def initialize(*response_names)
  @response_names = response_names.presence || %w(default values)
end
Mcconaghy answered 9/2, 2017 at 17:13 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.