sargas
sargas

Reputation: 6180

How to add arguments after splat arguments in method calls?

Ruby is an awesome language that confuses me sometimes (since I'm not that awesome). And splat arguments are responsible for some of that confusion. So enlighten me, please.

Given the following method:

def doSomething(with_this, *and_that)
  # ...
end

You can call that method with option 1:

doSomething("With this", "index 0", "index 1", "etc")

Or with option 2:

an_array = ["index 0", "index 1", "etc"]
doSomething("With this", *an_array)

But what if my method was defined like so:

def doSomething(with_this, *and_that, and_even_that)
  # ...
end

Note that there is a parameter after the splat argument

Question 1: Is there a way to add arguments for and_even_that other than using the following way?

an_array = ["index 0", "index 1", "etc"]
doSomething("With this", *an_array, "With that")

In the pursue of becoming a good Ruby programmer, I also wonder about those:

Extra questions:

Is it best practice not to use more than one splat argument in method definitions?

Is it best practice to leave splat arguments for last in method definitions?

Thank you in advance.

Upvotes: 1

Views: 935

Answers (1)

Uri Agassi
Uri Agassi

Reputation: 37409

You are confusing method declaration using splat, and method call using splat.

They are independant of each other:

def regular_method(arg1, arg2, arg3)
  #do something
end

def method_with_splat(arg1, *more_args)
  # do something
end

arr = [1, 2, 3]

regular_method(*arr) # works!

method_with_splat(4, *arr) # works! (arg1==4, more_args==[1,2,3])

method_with_splat(4, 5, *arr) # also ok! (arg1==4, more_args==[5,1,2,3])

method_with_splat(*arr, 4, 5, 6) # just fine! (arg1==1, more_args==[2,3,4,5,6])

So, in the same spirit:

def splat_in_the_middle(arg1, *more_args, last_arg)
  # do something
end

splat_in_the_middle(*arr, 4, 5, 6) # arg1==1, more_args==[2,3,4,5], last_arg==6

And expanding on that:

def splat_in_the_middle(arg1, *more_args, arg2, last_arg)
  # do something
end

splat_in_the_middle(*arr, 4, 5, 6) # arg1==1, more_args==[2,3,4], arg2==5, last_arg==6

Notice the first argument is assigned to the first parameter, the last arguments are always assigned to the last parameters, and the other become elements of the more_args array.

As for your extra questions:

  1. You cannot declare more than one splat in a single method definition. The simple reason is evident from the examples above - there is no way for the argument parser to know where one splat ends, and where the other begins:

    def two_splats(arg1, *splat1, arg2, *splat2)
      # do something!
    end
    # => syntax error!
    
    two_splats(1, 2, 3, 4, 5, 6) # arg1==1, splat1==[????] arg2==?, splat2==[????]
    

    though there is no problem calling a method with more than one splat:

    method_with_splat(*arr, *arr) # arg1==1, more_args=[2,3,1,2,3]
    
  2. If there is good reasoning to having your splat in the middle, and the arguments are readable, and easy to understand, there is no reason not to put the splat in the middle. A very useful use-case, for example might be that the last argument is an options hash:

    def splat_in_the_middle(first_arg, *one_or_more_other_args, options)
    

Upvotes: 3

Related Questions