[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

What does *args do?

Stedwick

2/20/2008 9:14:00 AM

I sometimes see funcs declared with def fun (blah, *args)

What does the *args do? Thanks!
30 Answers

Arlen Cuss

2/20/2008 9:18:00 AM

0

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

Hi,

It's called a "splat". A variable at the end of the function call with an
asterisk at the start [or elsewhere in Ruby 1.9?] "takes the slack", as
such, and allows an indefinite number of extra arguments. For example:

>> def fun blah, *args
>> puts "blah: #{blah.inspect}, args: #{args.inspect}"
>> end
=> nil
>> fun 1
blah: 1, args: []
=> nil
>> fun 1, 2
blah: 1, args: [2]
=> nil
>> fun 1, 2, 3
blah: 1, args: [2, 3]
=> nil
>>

Cheers,
Arlen.

7stud --

2/20/2008 9:53:00 AM

0

Philip Brocoum wrote:
> I sometimes see funcs declared with def fun (blah, *args)
>
> What does the *args do? Thanks!

Normally, if you define a method with two parameter variables, for
instance:

def show(x, y) #x, y are parameter variables
puts x
puts y
end

show(1, 2)

--output:--
1
2


...then you *must* call the method with two arguments(1 and 2 are the
arguments). Otherwise you get an error, for example:

show(1, 2, 3)

--output:--
'show': wrong number of arguments (3 for 2) (ArgumentError)


The * allows you to call a method and specify more arguments:

def show(x, *arr)
puts x

arr.each do |elmt|
puts elmt
end

end

show(1, 2, 3)
puts
show(1, 2, 3, 4)

--output:--
1
2
3

1
2
3
4


You still need to call show() with at least one argument so that ruby
can assign the first argument to the x parameter variable, but after
that you can specify any number of arguments in the method call. The
extra arguments are gathered up into an array and then assigned to the
variable name after the *, in this case that would be: arr.

If you have a method call like the following:

show(1, 2, 3, 4) #def show(x, *arr)

ruby assigns the argument 1 to the parameter variable x, and then ruby
creates an array to hold 2, 3, 4:

[2, 3, 4]

and then ruby assigns that array to the parameter variable arr:

arr = [2, 3, 4]


In effect the * in this definition:

def show(x, *arr)

says to ruby, "Please assign the first argument in the method call to x,
then gather up any additional arguments, stick them into an array, and
assign the array to the variable name to my right.




--
Posted via http://www.ruby-....

Stedwick

2/21/2008 1:03:00 AM

0

Got it, thanks. I love the term "splat" lol. Personally, I'm a big fan
of passing hashes {} as arguments.

Stedwick
http://www.philipbrocoum....

Arlen Cuss

2/21/2008 2:03:00 AM

0

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

Hi there,

On Thu, Feb 21, 2008 at 12:04 PM, Stedwick <philip.brocoum@gmail.com> wrote:

> Got it, thanks. I love the term "splat" lol. Personally, I'm a big fan
> of passing hashes {} as arguments. <http://www.philipbrocoum.com/...


In that case, the syntax which Rails often uses in Ruby might be of interest
to you:

>> def fn(a, b, opthash)
>> p a
>> p b
>> p opthash
>> end
=> nil
>> fn 1, 2, {:a => false}
1
2
{:a=>false}
=> nil
>> fn 1, 2, :a => false, :joker => 92
1
2
{:joker=>92, :a=>false}
=> nil
>>


If you just append hash arguments to the end of a function call, it'll
combine it into a hash and use it as the last parameter.

Arlen

Mark Bush

2/21/2008 2:35:00 PM

0

> What does the *args do? Thanks!

As well as the previously posted explanations of *args appearing in
a method argument list, it can also appear in a method body. In that
case, the array gets turned into a list.

That is, if a = [1, 2, 3, 4] then you can use *a to represent the list
of
values (here 1, 2, 3, 4). This is useful for adding the values to an
array:

[5, *a] # => [5, 1, 2, 3, 4]
[5, a] # => [5, [1, 2, 3, 4]]

In Ruby 1.8 this can only be at the end of the array, but in 1.9 it can
be anywhere:
[*a, *a] # => [1, 2, 3, 4, 1, 2, 3, 4] (in 1.9)

Also, if you want to pass the values as separate arguments to another
method:

puts *a # => same as: puts 1, 2, 3, 4
puts a # => same as: puts [1, 2, 3, 4]

You can even do multiple assignment this way:
b, c, d, e = *a
b # => 1
c # => 2
d # => 3
e # => 4

Note that this works with hashes, too. If a is a hash, then *a is the
equivalent
of:
b = a.to_a
*b
if you see what I mean.
--
Posted via http://www.ruby-....

Arlen Cuss

2/21/2008 2:46:00 PM

0

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

Hi,

On Fri, Feb 22, 2008 at 1:34 AM, Mark Bush <mark@bushnet.org> wrote:

> You can even do multiple assignment this way:
> b, c, d, e = *a
> b # => 1
> c # => 2
> d # => 3
> e # => 4
>

It's worth noting that this behaviour can be achieved without the splat
operator:
>> b, c, d, e = a # => [1, 2, 3, 4]
>> b # => 1
>> c # => 2
>> d # => 3
>> e # => 4


Arlen

Matthias Wächter

2/21/2008 3:29:00 PM

0

Arlen Cuss wrote:
>> You can even do multiple assignment this way:
>> b, c, d, e = *a
>> b # => 1
>> c # => 2
>> d # => 3
>> e # => 4
> It's worth noting that this behaviour can be achieved without the splat
> operator:
>>> b, c, d, e = a # => [1, 2, 3, 4]
>>> b # => 1
>>> c # => 2
>>> d # => 3
>>> e # => 4

I don't like this inconsistency in the language. Left is a list, right should be a list. Making it mate with both list and array can introduce tricky inconsistencies. I am in favor of dropping the latter and always'd require splat for multiple assignment. I think that is _too_ dynamic for an untyped, dynamic language like Ruby.

e.g.

def not_broken_up a
my_a, my_nil1 = a
if my_a != a
puts "Gotcha!"
else
p my_a
end
end

not_broken_up 1 # -> 1
not_broken_up "hi" # -> "hi"
not_broken_up({1=>1}) # -> {1->1}
not_broken_up [1] # -> Gotcha!
not_broken_up [1,2] # -> Gotcha!
not_broken_up [[1]] # -> Gotcha!

Stedwick

2/22/2008 3:39:00 AM

0


> I don't like this inconsistency in the language. Left is a list, right should be a list. Making it mate with both list and array can introduce tricky inconsistencies. I am in favor of dropping the latter and always'd require splat for multiple assignment. I think that is _too_ dynamic for an untyped, dynamic language like Ruby.

I think it makes perfect sense. If you are doing multiple assignments,
do this:

a = b = c = "hi"

But it's pretty cool to be able to do this:
a, b, c = ["hi", "hello", "wassa"]

Mark Bush

2/22/2008 9:09:00 AM

0

Philip Brocoum wrote:
> I think it makes perfect sense. If you are doing multiple assignments,
> do this:
>
> a = b = c = "hi"
>
> But it's pretty cool to be able to do this:
> a, b, c = ["hi", "hello", "wassa"]

The problem is: what is the value of a after:

a, b, c = d

?
The answer is: it depends. If d is an array, then a becomes d[0],
otherwise a becomes d. Since you can write:

a, b, c = "hi", "hello", "wassa"

setting each value, and:

a, b, c = "hi"

sets a to "hi" and the other two become nil and since ["hi", "hello",
"wassa"] is a single object, it seems natural to expect that:

a, b, c = ["hi", "hello", "wassa"]

should set a to the array and set b & c to nil, but it doesn't. Why
should a be set differently in the following cases:

a, b, c = ["hi", "hello", "wassa"]
a, b, c = ["hi", "hello", "wassa"], "hey"

You would expect that each of the following would result in a ending up
with the value of d:

a = d
a, b = d
a, b, c = d

but it doesn't. If d is an array, then "a = d" sets a to the value of
d, but the others set it to d[0]. If d is not an array, then a takes the
value of d in all cases. Having an object change implicitly into
something else like this is definitely a gotcha.

Further, consider this example:

a = [[1, 2, 3]]
b, c, d = *a

What is the value of b? Since the multiple assignment is "equivalent"
to:

b, c, d = [1, 2, 3]

it would seem that the way arrays automagically expand would result in b
becoming 1, but actually b becomes the array [1, 2, 3] meaning that
automagic expansion is not happening. So even the inconsistency is
inconsistent!

The semantics of assignment should not change just because the class of
something on the rhs changes.
--
Posted via http://www.ruby-....

Matthias Wächter

2/22/2008 10:46:00 AM

0

Mark,

thanks for your perfect explanation of the problem, you clearly make my point. :)

Mark Bush wrote:
> The problem is: what is the value of a after:
>
> a, b, c = d
>
> ?
> The answer is: it depends. If d is an array, then a becomes d[0],
> otherwise a becomes d. Since you can write:
>
> a, b, c = "hi", "hello", "wassa"
>
> setting each value, and:
>
> a, b, c = "hi"

To make inconsistencies even more stupid, we could specify that

a,b,c,d,e = "aeiou"

results in a=="a", b=="e", c=="i", d=="o", e=="u".

or

a,b,c,d = 5

could be interpreted as a bit-wise split assignment such that a==0, b==1, c==0, d==1. I see no point in allowing an array to be treated specially, even more so as there is the one-character splat operator available.

> Further, consider this example:
>
> a = [[1, 2, 3]]
> b, c, d = *a
>
> What is the value of b? Since the multiple assignment is "equivalent"
> to:
>
> b, c, d = [1, 2, 3]
>
> it would seem that the way arrays automagically expand would result in b
> becoming 1, but actually b becomes the array [1, 2, 3] meaning that
> automagic expansion is not happening. So even the inconsistency is
> inconsistent!

Yeah, thanks for this perfect example of the matter!

> The semantics of assignment should not change just because the class of
> something on the rhs changes.

My words.

Was this discussed already so that we know what Matz thinks about it, or should we bring this topic up on ruby-core?

- Matthias