strange behaviour if exploding parameters

J

Jarmo Pertman

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:0x04b7e510@(irb):9>
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:0x04b2c880@(irb):12>
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
 
B

Brian Candler

Jarmo said:
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=> Array

So I think you want:

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

So now you are demonstrating:
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:
(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:0x04b2c880@(irb):12>
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.
 
J

Josh Cheek

[Note: parts of this message were removed to make it a legal post.]

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:0x04b7e510@(irb):9>
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:0x04b2c880@(irb):12>
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
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
 
J

Jarmo Pertman

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

Jarmo
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,701
Latest member
XavierQ83

Latest Threads

Top