In Ruby, how does parallel assignment such as a, b = b, a swap two values without a temporary variable?
answer
- right side evaluated first
- extras dropped, missing become nil
- one splat collects the rest
- parentheses destructure nested arrays
- the expression returns the right side
basics
~10 sRuby evaluates every value on the right-hand side first, then assigns them to the left-hand targets in order, so a, b = b, a reads both old values before writing either one.
solid answer
~40 sIn a multiple assignment Ruby **evaluates all the right-hand values before storing any of them**, so `a, b = b, a` reads the old `b` and the old `a`, then writes them crosswise; no temporary is needed. The same syntax destructures: a single array on the right is unpacked (`first, last = [1, 2]`), extra values are dropped, missing ones become `nil`, and one `*` gathers the rest (`head, *tail = list`). Parentheses destructure a nested array (`a, (b, c) = 1, [2, 3]`). Targets can be instance variables, globals, setters or index assignments, so `arr[i], arr[j] = arr[j], arr[i]` swaps elements. Since Ruby 3.1, the left-hand receivers such as `arr` are evaluated before the right-hand values, matching single assignment.
code
ruby · 12 linesreadings = [30, 10, 20]
readings[0], readings[1] = readings[1], readings[0]
p readings # => [10, 30, 20]
head, *tail = readings
p head, tail # => 10, then [30, 20]
low, high = readings.minmax
p [low, high] # => [10, 30]
name, (lat, lon) = "depot", [52.1, 4.3]
p lat # => 52.1go deeper
Know the swap idiom and what happens with too many or too few values on the right.
Explain that the right side is evaluated before any target is written, and use the splat and parentheses to destructure.
Watch for silent nil when a method returns fewer values than the caller unpacks, and know the Ruby 3.1 evaluation-order change for receivers with side effects.
Encourage destructuring where it clarifies intent, such as unpacking return pairs, and discourage long parallel assignments that hide unrelated state changes.
## The mechanism A **multiple assignment** (also called parallel assignment) has several targets on the left of `=` and one or more values on the right. Ruby builds the full list of right-hand values **before** it writes to any target. That is what makes the swap work: ```ruby a, b = 1, 2 a, b = b, a p [a, b] # => [2, 1] ``` 1. The right side `b, a` is evaluated to the list `[2, 1]` using the current values. 2. The first value is assigned to `a`. 3. The second value is assigned to `b`. A naive `a = b; b = a` would lose the original `a`; multiple assignment avoids that because step 1 completes before step 2 starts. ## Matching rules | Code | Result | |---|---| | `a, b = 1, 2, 3` | `a = 1`, `b = 2`; the extra `3` is dropped | | `a, b = 5` | `a = 5`, `b = nil` | | `a, b = [1, 2]` | a single array on the right is unpacked: `a = 1`, `b = 2` | | `a, *b = 1, 2, 3` | `a = 1`, `b = [2, 3]` | | `*a, b = 1, 2, 3` | `a = [1, 2]`, `b = 3` | | `first, *rest = [7]` | `first = 7`, `rest = []` | | `a, (b, c) = 1, [2, 3]` | nested destructuring: `b = 2`, `c = 3` | - Only **one** splat is allowed per level of the left-hand side; a parenthesised group counts as its own level and may have its own splat. - A splat target always receives an **array**, possibly empty, never `nil`. - Ruby never raises for a count mismatch in assignment: surplus values are ignored and missing ones are `nil`. ## Targets beyond locals Any assignable thing can appear on the left: - instance, class and global variables: `@min, @max = values.minmax`; - setter methods: `self.width, self.height = 640, 480` calls `width=` then `height=`; - index assignment: `list[i], list[j] = list[j], list[i]` swaps two elements in place. A method that ends with `return low, high` returns an array, and the caller can unpack it directly: `low, high = bounds(values)`. ## Evaluation order and the Ruby 3.1 change Before Ruby 3.1, multiple assignment evaluated the right-hand values first and the left-hand receivers afterwards. Ruby 3.1 made it match single assignment, where the receiver is evaluated before the value. For `foo[0], bar.baz = a, b` the order is now: 1. `foo` 2. `bar` 3. `a` 4. `b` 5. `[]=` called on `foo` 6. `baz=` called on `bar` The values are still all computed before any assignment method runs, so swaps behave the same; only code whose receiver expressions have side effects can notice the difference. ## The value of the expression A multiple assignment is itself an expression, and its value is the **right-hand side as an array**, not the last value assigned: `x = (a, b = 1, 2)` leaves `x` as `[1, 2]`. This rarely matters, but it explains what an `irb` session echoes after a swap. ## Parallel is not chained assignment - `a, b = [], []` creates **two** separate arrays, one per variable. - `a = b = []` is chained assignment: it evaluates `b = []` first and assigns the **same** array to `a`, so `a << 1` also shows up in `b`. - Mixing them up is a common source of shared-state bugs when initialising several collections at once. ## When to use it - Swapping two values or two array elements. - Unpacking a method's multiple return values. - Splitting a list into head and tail. Avoid long parallel assignments of unrelated values (`a, b, c, d = 1, x, "y", nil`); separate lines read better and are easier to change.
- What do a and b hold after a, b = 5, and why no error?`a` is 5 and `b` is `nil`. Multiple assignment pads missing values with `nil` and ignores surplus ones, so a count mismatch never raises. That is convenient, but it also means a method that unexpectedly returns one value instead of two silently yields `nil` for the second variable.
- What changed about multiple assignment in Ruby 3.1?Its evaluation order. Before 3.1, all right-hand values were evaluated before the left-hand receivers. Since 3.1 the receivers on the left (for example `foo` in `foo[0]`) are evaluated first, then the right-hand values, then the assignment methods, matching single assignment. Swaps are unaffected because values are still computed before any assignment runs.
saying these in an interview costs you the question
- a, b = b, a assigns a first, so both variables end up equal
- Assigning three values to two variables raises ArgumentError
- A splat target gets nil when there is nothing left to collect
- Multiple assignment returns the last value assigned
- Swapping array elements this way needs a temporary copy of the array