Strange behaviour if exploding parameters

Hello!

I’ve just happened to find strange behaviour when trying to explode
parameters.

Why doesn’t it work?
irb(main):007:0> lambda {|*parameters| *parameters.class}
SyntaxError: compile error
(irb):7: syntax error, unexpected ‘}’, expecting tCOLON2 or ‘[’ or ‘.’
from (irb):7
from :0

class is Array if 0 or more parameters given
irb(main):009:0> l = lambda {|*parameters| p *parameters.class}
=> #Proc:[email protected]:9(irb)
irb(main):010:0> l[]
Array
=> nil

class is Array if some parameters given
irb(main):012:0> l = lambda {|*parameters| x = *parameters; p x.class}
=> #Proc:[email protected]:12(irb)
irb(main):013:0> l[1,2]
Array
=> nil

class is NilClass instead of Array?
irb(main):014:0> l[]
NilClass
=> nil

Any ideas why class is NilClass instead of Array if *parameters is
assigned to local variable? I’d expect it to be always an Array and if
no parameters given then an empty Array.

Best Regards,
Jarmo

Jarmo P. wrote:

Why doesn’t it work?
irb(main):007:0> lambda {|*parameters| *parameters.class}
SyntaxError: compile error
(irb):7: syntax error, unexpected ‘}’, expecting tCOLON2 or ‘[’ or ‘.’
from (irb):7
from :0

Your problem is basically this:

a = [1,2,3]
=> [1, 2, 3]

*a.class
SyntaxError: compile error
(irb):11: syntax error, unexpected ‘\n’, expecting tCOLON2 or ‘[’ or ‘.’
from (irb):11
from :0

a.class
=> Array

So I think you want:

irb(main):002:0> lambda {|*parameters| parameters.class}
=> #Proc:[email protected]:2(irb)

class is Array if 0 or more parameters given
irb(main):009:0> l = lambda {|*parameters| p *parameters.class}
=> #Proc:[email protected]:9(irb)
irb(main):010:0> l[]
Array
=> nil

So now you are demonstrating:

p *a.class
Array
=> nil

This is because “p” is a method, and so you can use splat to expand its
arguments. I think what you’ve written is equivalent to:

irb(main):023:0> p(*(a.class))
Array
=> nil

Strangely, * works on a non-array here. Possibly you are relying on
implicit to_a:

a.class.to_a
(irb):24: warning: default `to_a’ will be obsolete
=> [Array]

class is Array if some parameters given
irb(main):012:0> l = lambda {|*parameters| x = *parameters; p x.class}
=> #Proc:[email protected]:12(irb)
irb(main):013:0> l[1,2]
Array
=> nil

class is NilClass instead of Array?
irb(main):014:0> l[]
NilClass
=> nil

Of course, same as this:

irb(main):025:0> x = *[]
=> nil

You’re basically doing a multiple-assignment with zero values on the
right-hand side, so it gets nil. Similarly:

a,b,c = 1,2
=> [1, 2]

c
=> nil

Any ideas why class is NilClass instead of Array if *parameters is
assigned to local variable? I’d expect it to be always an Array and if
no parameters given then an empty Array.

You need to look at the value ‘parameters’, and that’s what you’ll see.

If you take the parameters array and splat it with *, then you’re asking
for ruby to do more.

On Wed, Jun 16, 2010 at 9:01 AM, Jarmo P. [email protected]
wrote:

   from :0

class is Array if some parameters given
=> nil

Hi, I think you might be a bit confused about how * works in your param
list. It will aggregate all the params into a single array:
lambda { |*params| params }.call 1 , 2 , 3 # => [1, 2, 3]

So you can call class on it
lambda { |*params| params.class }.call 1 , 2 , 3 # => Array

return is a method invocation (at least in my mind) so you can “explode”
the
brackets here too, and it becomes like “return 1 , 2 , 3” which is
syntactically the same as “call 1 , 2 , 3”
lambda { |*params| return *params }.call 1 , 2 , 3 # => [1, 2, 3]

But there are two things that don’t really make sense. “1 , 2 , 3” all
by
itself is not valid Ruby. Leaving it on its own line like this
lambda { |*params| *params }.call 1 , 2 , 3 # => syntax error
Is like saying this
lambda { |*params| 1 , 2 , 3 }.call 1 , 2 , 3 # => syntax error

Since that is not valid, then what does it mean to say *params.class ?
Well,
first of all, the .class is evaluated first (not sure how to say that,
“higher binding” maybe?) The class is an Array. so this becomes “*Array”
which is probably not what you want, and only works, again, when passing
it
to return.
lambda { |*params| return *params.class }.call 1 , 2 , 3 # => Array
lambda { |*params| *params.class }.call 1 , 2 , 3 # => syntax error

So, in summary, I think this is what you were looking for:
lambda { |*params| params.class }.call 1 , 2 , 3 # => Array

Brian and Josh - thank You both for these fine answers. I got my
understanding now about what’s happening behind the scenes.

Jarmo