Parentheses in block variables

arrays, parentheses, ruby, ruby-1.9.3, splat

Solution

It's because of the syntax of parallel assignment.

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

So `a.each` has only one element to iterate, which is `[:a, :b, :c]`.

In the first case:

(x, y), z = [:a, :b, :c]
#=> x == :a, y == nil, z == :b

Here `(x, y)` is an array to match the first element `:a`, and `x` gets it, then `z` simply matches the second element `:b`.

And in the second case:

(x, y) = [:a, :b, :c]
#=> x == :a, y == :b

Here `(x, y)` as an entire array matches the array `[:a, :b, :c]`, so `x` and `y` get `:a` and `:b` respectively.

This is just like requiring the "args + optional args (keyword args) + rest args" combination match provided arguments. It is just smart enough to take arguments by sequence.

Another smart example:

(a,b) = 1,2
=> [1, 2] # array match
#=> a == 1, b == 2

(a,b)=[1,2]
=> [1, 2] # array match
#=> a == 1, b == 2

In either case above, it will simply make the best guess on what it should take.

Problem

Given ``` a = [[:a, :b, :c]] ``` 1) I understand this ``` a.each{|(x, y), z| p z} # => :b ``` that there are two variables `(x, y)` and `z`, so the third element `:c` is thrown away, and `z` matches `:b`. And I understand this ``` a.each{|(x, y), z| p y} # => nil ``` that `(x, y)` matches `:a`, and since it is not an array, there are no elements to it, and so `y` matches `nil`. But how does ``` a.each{|(x, y), z| p x} # => :a ``` work? I expect `nil` to be returned. 2) Why are the return values like this? ``` a.each{|(x, y)| p x} #=> :a a.each{|(x, y)| p y} #=> :b ``` I expect them to both return `nil`.

Original source