Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set a default value for a splat argument in Ruby

Tags:

ruby

splat

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?

like image 630
jordanpg Avatar asked Apr 03 '13 20:04

jordanpg


2 Answers

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.

like image 149
vlasits Avatar answered Sep 28 '22 08:09

vlasits


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.

like image 26
Thomas Klemm Avatar answered Sep 28 '22 08:09

Thomas Klemm