7

I'm not sure what exactly is going on with the code snippet below.

>> a, b = ["ho", "hey"]
=> ["ho", "hey"]
>> a
=> "ho"
>> b
=> "hey"    
>> c, d = "foo", "bar"
=> ["foo", "bar"]
>> c 
=> "foo"
>> d
=> "bar"
>> a, b = ["blerg"], ["baz"]
=> [["blerg"], ["baz"]]
>> a
=> ["blerg"]
>> b 
=> ["baz"]

Why wouldn't line 1 return a => ["ho"]?

So behind the scenes, what's the difference between these three assignments (a, b = ["ho", "hey"], c, d = "foo", "bar", a, b = ["blerg"], ["baz"])?

4 Answers 4

11
a, b = ["ho", "hey"] 

a is assigned the first element of the array, which is the string "ho". Nothing weird.

a, b = ["blerg"], ["baz"]

a, b = [["blerg"], ["baz"]]

These two are the same, as you can see by their return values. So a is assigned the first element, which is an array with one element: ["blerg"].

Similarly,

c, d = "foo", "bar"

Is the same as

c, d = ["foo", "bar"]
Sign up to request clarification or add additional context in comments.

1 Comment

Beware of a = b = []. Sometimes I intend a,b = [], and instead I write a = b = []. And the later will assign a reference of b to a, which for use is not what you want. DONATO
7

In Ruby, = takes a list of variables on the left, and a list of expressions on the right. It assigns the the first variable to the value of the first expression, the second variable the value of the second expression, and so on. If there are more variables than expressions, the leftover variables get assigned the value nil.

> a, b, c, d = "foo", 2+3, Array.new(2, 3), [:c, :d]
> a     # => "foo"
> b     # => 5
> c     # => [3, 3]
> d     # => [:c, :d]
> e     # => nil

There are two exceptions:

Left side has only one variable, right side has multiple expressions

In this case, the above rule would say that the variable just gets set to the value of the first expression on the right. Instead, the variable gets set to the Array consisting of the values of the expression on the right. In the example below, we see a gets the value [:b, :c], instead of just :b:

> a = :b, :c
> a    # => [:b, :c]

This is equivalent to:

> *a = :b , :c
> a    # => [:b, :c]

The other exception:

The left side has multiple variables, the right side has only one expression and it's an Array

Again, the original rule would imply that the first variable gets set to that whole Array, and the rest of the variables would be nil. However, that Array effectively ends up getting replaced with the list of its elements, and then = reverts to the "default" behaviour described in the beginning:

> a, b, c = [:d, [:e, :f]]
> a    # => :d
> b    # => [:e, :f]
> c    # => nil

This is equivalent to a, b, c = *[:d, [:e, :f]], or just a, b, c = :d, [:e, :f]

1 Comment

didnt know about the left side one variable case. Cool!
0

In the examples you point out, there are 2 different structures being used on the right hand side of the multiple assignment:

Multiple assignment from a simple array

array = ["item1", "item2"]
a, b = array
# a => "item1"
# b => "item2"

Multiple assignment from an array who's elements are themselves single element arrays (aka: a multi-dimensional array)

array = [["item1"], ["item2"]]
a, b = array
# a => ["item1"]
# b => ["item2"]

Multiple assignment unwraps only the first level of a multi-dimensional array and allows you to assign those elements to multiple variables on the left hand side of the expression. So when you do this with a multi-dimensional array, it takes the first element wich is ["item1"] and assigns in to a, then moves on to the next element, which is ["item2"] and assigns it to b. The multiple assignment doesn't "dig deeper" into the multi-dimensional array, it performs the assignment from the first level of elements.

Comments

0

The assignment operator in the Ruby Language allow Multiple assignments (aka: parallel assignment).

Say lvalue the left side variables or attributes on the left side of the assignment operator (=) and say rvalue the right side values.

By Multiple assignments you can assign one comma delimited list to another, with corresponding variables on the left side getting corresponding values from the right

first parallel assignment

a, b = ["ho", "hey"]

if the last rvalue is an array, you can prefix it with an asterisk, which effectively expands it into its constituent values in place. the asterisk is not necessary if the rvalue is the only thing on the right-hand side the array will be expanded automatically.

To better understand, try this:

>> a,b,c =  "1",*["ho", "hey"]
=> ["1", "ho", "hey"]
>> a
=> "1"
>> b
=> "ho"
>> c
=> "hey"

let's see again:

>> a,b,c =  "1",["ho", "hey"]
=> ["1", ["ho", "hey"]]
>> a
=> "1"
>> b
=> ["ho", "hey"]
>> c
=> nil

as you can see, if we don't prefix the array with the * then the array is not expanded.

second parallel assignment

c, d = "foo", "bar"

"foo", "bar" are two literal Strings assigned to the corresponding variable on the left side.

third parallel assignment

a, b = ["blerg"], ["baz"])?

["blerg"] and ["baz"] are two Array each one containing one element of class String;

therefore each "Array of a sigle String" is assigned to the corresponding variable on the left side.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.