LaunchKit
All quizzes
Ruby 0 views

Swapping two variables with a, b = b, a

Question

In Ruby, what is the idiomatic way to swap the values of two variables in a single line?

The correct answer is

Explanation

TL;DR

a, b = b, a. Multiple assignment evaluates the entire right-hand side first, bundling the values together, then assigns them to the left-hand targets. Both reads happen before either write, so the values cross over without a temporary variable.

Step by step

a = 1
b = 2

a, b = b, a

a # => 2
b # => 1

The whole expression evaluates to the array of right-hand values:

a = 1
b = 2

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

Under the hood

puts RubyVM::InstructionSequence.compile("a, b = b, a").disasm

Output on Ruby 4.0, with the == disasm header line trimmed:

local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] a@0        [ 1] b@1
0000 getlocal_WC_0                          b@1                       (   1)[Li]
0002 getlocal_WC_0                          a@0
0004 newarray                               2
0006 dup
0007 expandarray                            2, 0
0010 setlocal_WC_0                          a@0
0012 setlocal_WC_0                          b@1
0014 leave

Both getlocal reads run before either setlocal write: the current values of b and a are collected into an array (newarray), duplicated so the expression has a return value (dup), then unpacked onto the targets (expandarray). This read-everything-then-write-everything ordering is what makes the swap safe.

Edge cases

More than two targets rotate the same way:

x, y, z = 1, 2, 3

x, y, z = z, x, y

[x, y, z] # => [3, 1, 2]

Any assignable target works, not just local variables:

arr = [1, 2]
arr[0], arr[1] = arr[1], arr[0]
arr # => [2, 1]

h = { a: 1, b: 2 }
h[:a], h[:b] = h[:b], h[:a]
h # => {a: 2, b: 1}

Why the other choices fail

temp = a; a = b; b = temp works, but it takes three statements and a throwaway variable; multiple assignment removes exactly that noise. a.swap(b) does not exist, and no method could implement it: a method cannot rebind its caller's local variables. The XOR trick needs its results assigned (a ^= b and friends); the bare expression a ^ b ^ a computes a value and changes nothing:

a = 1
b = 2

a ^ b ^ a # => 2

a # => 1
b # => 2

Share this quiz

Comments

No comments yet. Be the first.

Only used to confirm and publish your comment. Never shown publicly, never shared.

Markdown: **bold**, `code`, ```fenced blocks```, > quotes, [links](url). HTML and images are not rendered.