Temp-Free Variable Swap
This page shows how Perl swaps two variables in a single statement without a temporary placeholder. The trick relies on how list assignment evaluates expressions, and it scales to rotations, hash slices, and simple algorithms like Fibonacci.Three lines and a throwaway variable. That pattern reads like a form you fill out twice.my $temp = $x; $x = $y; $y = $temp;
Perl handles the same job in one line:
No placeholder variable and no extra bookkeeping. The statement works because list assignment evaluates the right side completely before it touches the left side.($x, $y) = ($y, $x);
Part 1: WHY THIS WORKS
The mechanism depends on evaluation order. Perl resolves the entire right-hand expression into a list before it writes anything to the left-hand variables.Here is what happens step by step:($x, $y) = ($y, $x);
The right side resolves into a fixed list of values before the left side sees anything. The original values sit safely inside that intermediate list while the assignment runs.STEP WHAT HAPPENS ---- ----------------------------------------- 1 Evaluate ($y, $x) - builds a temporary list 2 That list contains the OLD values of $y and $x 3 Assign that list to ($x, $y) 4 $x gets the old $y, $y gets the old $x
Perl builds the list first, then writes to the variables. Two phases, one statement.
Part 2: THE C PROGRAMMER'S PAIN
In C, you have no choice:Python allowsint temp = x; x = y; y = temp;
x, y = y, x for the same reason as Perl. Many other languages still force you to declare a placeholder variable.
Some developers try the XOR trick instead:
Three operations with no placeholder, but the code is hard to read. It also breaks whenx ^= y; y ^= x; x ^= y;
x and y reference the same memory location. The trick is clever, fragile, and ugly all at once.
Perl's list assignment avoids every one of those problems. The language was designed to work this way.
Part 3: THREE OR MORE
The pattern scales to any number of variables. You can rotate three values like this:Before:($a, $b, $c) = ($b, $c, $a);
After:$a = 1, $b = 2, $c = 3
That is a left rotation in one line. Every value shifts one position left, and the leftmost value wraps to the right.$a = 2, $b = 3, $c = 1
A right rotation just reverses the direction:
You can run this with four, five, or ten variables. The rule stays the same: the entire right side evaluates first, every time.($a, $b, $c) = ($c, $a, $b);
Part 4: PRACTICAL USES
You can sort two values so the smaller one comes first:One line and a conditional swap. The statement modifier reads almost like plain English: swap the values if they sit in the wrong order.($min, $max) = ($max, $min) if $min > $max;
You can also swap hash values directly:
That uses a hash slice on both sides. The same evaluation rule applies, so the right side resolves fully before the left side changes.@hash{qw(first last)} = @hash{qw(last first)};
You can normalize coordinates so (x1, y1) always lands at the top-left corner of a bounding box:
Two clean swaps without cluttering the namespace with placeholders.($x1, $x2) = ($x2, $x1) if $x1 > $x2; ($y1, $y2) = ($y2, $y1) if $y1 > $y2;
You can toggle between two states with the same pattern:
Every swap acts as a toggle, and every toggle acts as a swap. The mechanism stays the same.my ($on, $off) = ("active", "inactive"); # Toggle current state ($on, $off) = ($off, $on); say "Current: $on"; # Current: inactive
Part 5: DECONSTRUCTING THE MAGIC
Let us prove this is not just syntactic sugar. Imagine what would happen if Perl assigned left to right at the same time:Perl does not work that way. The right-hand list becomes a snapshot before assignment begins. The values freeze in place.# HYPOTHETICAL broken behavior (not how Perl works!) ($x, $y) = ($y, $x); # If it assigned $x = $y first... # then $y = $x would use the NEW $x (which is already $y) # Result: both variables equal $y. Broken.
You can verify the behavior yourself:
It works every time. The snapshot guarantees the result.my $x = "alpha"; my $y = "omega"; ($x, $y) = ($y, $x); say "x = $x"; # x = omega say "y = $y"; # y = alpha
Part 6: ARRAY ELEMENT SWAPS
The same trick works with array elements:That swaps the first and last elements. Array slices follow the same evaluation rules as list assignment.@arr[0, -1] = @arr[-1, 0];
You can reverse the first and last three elements of an array like this:
The code looks busy, but it states exactly what it does.@arr[0, 1, 2, -3, -2, -1] = @arr[-3, -2, -1, 0, 1, 2];
For adjacent swaps inside a loop, which form the core of a bubble sort:
No placeholder variable appears anywhere. The list assignment handles the exchange.for my $i (0 .. $#arr - 1) { if ($arr[$i] > $arr[$i + 1]) { @arr[$i, $i + 1] = @arr[$i + 1, $i]; } }
Part 7: STRING TRICKS
You can swap words inside a string by combining capture groups with list assignment:That is a regex approach, but a cleaner list assignment version looks like this:my $str = "hello world"; ($str) = $str =~ s~(\w+)(\s+)(\w+)~$3$2$1~r;
Or you can rebuild the string in one step:my ($first, $second) = split /\s+/, $str; ($first, $second) = ($second, $first); $str = "$first $second";
Different tool, same spirit. Perl gives you several valid options.$str = join ' ', reverse split /\s+/, $str;
Swapping hash keys and values also becomes a one-liner:
Themy %original = (a => 1, b => 2, c => 3); my %reversed = reverse %original; # %reversed is (1 => 'a', 2 => 'b', 3 => 'c')
reverse function flips the list, and hash assignment pairs the values back together. The operation is not a variable swap in the strict sense, but the same evaluation principle applies. Perl builds the full list before the hash consumes it.
Part 8: THE FIBONACCI CONNECTION
The Fibonacci sequence fits the temp-free swap naturally:Each iteration turnsmy ($a, $b) = (0, 1); for (1 .. 20) { say $a; ($a, $b) = ($b, $a + $b); }
$b into the sum of the old $a and $b, while $a becomes the old $b. No placeholder is needed because the right side evaluates completely before assignment.
Most languages require three lines for the same step:
Perl's version reads like the mathematical definition. Two values, one transformation, one line.temp = a a = b b = temp + b
fib(n): ($a, $b) = ($b, $a + $b) 0 1 1 2 3 5 8 13 21 34 \/ \/ \/ \/ \/ \/ \/ \/ /\ /\ /\ /\ /\ /\ /\ /\ 1 1 2 3 5 8 13 21 34 55
Part 9: MULTIPLE RETURN VALUES
Perl subroutines return lists, and list assignment makes consuming those returns straightforward:If you want the return values in a different order, you just swap on the receiving end:sub divide { my ($a, $b) = @_; return (int($a / $b), $a % $b); } my ($quotient, $remainder) = divide(17, 5); say "17 / 5 = $quotient remainder $remainder";
The list is the native data structure in Perl. Assignment to lists is how Perl thinks. The temp-free swap is not a special case. It is just list assignment doing what list assignment does.my ($remainder, $quotient) = reverse divide(17, 5);
Part 10: UNDER THE HOOD
What does Perl actually do internally when it sees a list assignment? The interpreter follows three steps:A temporary still exists, but it lives on the stack instead of in your code. Perl manages it internally. You do not name it, declare it, or clean it up. The interpreter handles the bookkeeping.1. Evaluates every element on the right side 2. Stores them in a temporary internal list (on the stack) 3. Assigns from that list to the left side, one element at a time
This is also why you can safely run:
Perl does not reverse the array in place and overwrite itself. It builds the reversed list first, then assigns. The old@array = reverse @array;
@array contents survive long enough for the right side to finish.
Understanding this distinction matters. You are not avoiding temporary storage. You are letting Perl handle it for you instead of doing it by hand. That is not laziness. That is abstraction.
Part 11: THE TAKEAWAY
The temp-free swap is not a golf trick. It is not obfuscation. It is idiomatic Perl.When you write ($x, $y) = ($y, $x), you communicate intent more clearly than three lines with a placeholder variable. Anyone reading your code sees that two values are being swapped in a single glance.
The rule is simple: the right side is fully evaluated before the left side is assigned. That is the entire mechanism. Once you internalize it, you will rarely reach for a temp variable again.
perl.gg+---------+ | $temp | +---------+ | [VACANT] | "Position eliminated. Perl doesn't need you." .--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/