Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why am I getting an "Unexpected *" error when using the * (asterisk) operator as a method parameter?

Tags:

ruby

I'm learning Ruby at the moment and I came across this peculiar situation.

When I run the following code, I get the output shown further below.

Working Code:

def hello(a,b=1,*c,d,e,f)
  p a,b,c,d,e,f
end

hello(1,2,3,4,5)

Working Code Output:

1
2
[]
3
4
5

However, upon editing the code so that the parameter 'e' is the catch all parameter, I get the error shown further below.

Failing Code:

def hello(a,b=1,c,d,*e,f)
    p a,b,c,d,e,f
end

hello(1,2,3,4,5)

Failing Code Output:

a.rb:1: syntax error, unexpected *
def hello(a,b=1,c,d,*e,f)
                     ^
a.rb:1: syntax error, unexpected ')', expecting '='
a.rb:3: syntax error, unexpected keyword_end, expecting end-of-input

I'm using ruby 2.3.1p112 (2016-04-26 revision 54768) on Ubuntu.

I'm interested in knowing why the second snippet of code fails.

Edit:

The following code fails as well.

def hello(a,b=1,c,d,e,*f)
    p a,b,c,d,e,f
end

hello(1,2,3,4,5)

And I get a similar error

a.rb:1: syntax error, unexpected *
def hello(a,b=1,c,d,e,*f)
                       ^
a.rb:3: syntax error, unexpected keyword_end, expecting end-of-input
like image 418
Steve Avatar asked Jan 31 '17 21:01

Steve


1 Answers

The relevant documentation is here and here's a related question. They don't seem to cover all cases though.

Here's what I could gather :

  • no more than one splat operator (*args) can be used.
  • multiple default arguments can be used (a=1, b=2).
  • default arguments must be to the left of the splat operator.
  • multiple default arguments must come directly one after the other.
  • if default arguments and splat operator are used, the default arguments must come right before the splat operator.
  • if the above rules are followed, default arguments and splat operator can be anywhere in the arguments list.

For readability, it might be a good idea to :

  • put the splat operator as the last argument
  • avoid putting default arguments in the middle

Here are valid method definitions :

def  hello(a = 1, b)            ;end
def  hello(a, b = 2)            ;end
def  hello(a = 1, b = 2)        ;end
def  hello(a = 1, b = 2, c)     ;end
def  hello(a, b = 2, c = 3)     ;end
def  hello(a, b = 2, *c)        ;end
def  hello(a, b = 2, *c, d)     ;end
def  hello(a = 1, b = 2, *c, d) ;end

For your second example, this syntax would be fine :

def hello(a,b,c,d=1,*e,f)
    p a,b,c,d,e,f
end

For a more complete example with block and keyword arguments, see @JörgWMittag's excellent answer.

like image 126
Eric Duminil Avatar answered Oct 14 '22 07:10

Eric Duminil