◈ Netsurfer / perl.gg / Temp-Free Variable Swap

Temp-Free Variable Swap

2026-03-08

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.
my $temp = $x; $x = $y; $y = $temp;
Three lines and a throwaway variable. That pattern reads like a form you fill out twice.

Perl handles the same job in one line:

($x, $y) = ($y, $x);
No placeholder variable and no extra bookkeeping. The statement works because list assignment evaluates the right side completely before it touches the left side.

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.
($x, $y) = ($y, $x);
Here is what happens step by step:
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
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.

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:
int temp = x; x = y; y = temp;
Python allows 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:

x ^= y; y ^= x; x ^= y;
Three operations with no placeholder, but the code is hard to read. It also breaks when 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:
($a, $b, $c) = ($b, $c, $a);
Before:
$a = 1, $b = 2, $c = 3
After:
$a = 2, $b = 3, $c = 1
That is a left rotation in one line. Every value shifts one position left, and the leftmost value wraps to the right.

A right rotation just reverses the direction:

($a, $b, $c) = ($c, $a, $b);
You can run this with four, five, or ten variables. The rule stays the same: the entire right side evaluates first, every time.

Part 4: PRACTICAL USES

You can sort two values so the smaller one comes first:
($min, $max) = ($max, $min) if $min > $max;
One line and a conditional swap. The statement modifier reads almost like plain English: swap the values if they sit in the wrong order.

You can also swap hash values directly:

@hash{qw(first last)} = @hash{qw(last first)};
That uses a hash slice on both sides. The same evaluation rule applies, so the right side resolves fully before the left side changes.

You can normalize coordinates so (x1, y1) always lands at the top-left corner of a bounding box:

($x1, $x2) = ($x2, $x1) if $x1 > $x2; ($y1, $y2) = ($y2, $y1) if $y1 > $y2;
Two clean swaps without cluttering the namespace with placeholders.

You can toggle between two states with the same pattern:

my ($on, $off) = ("active", "inactive"); # Toggle current state ($on, $off) = ($off, $on); say "Current: $on"; # Current: inactive
Every swap acts as a toggle, and every toggle acts as a swap. The mechanism stays the same.

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:
# 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.
Perl does not work that way. The right-hand list becomes a snapshot before assignment begins. The values freeze in place.

You can verify the behavior yourself:

my $x = "alpha"; my $y = "omega"; ($x, $y) = ($y, $x); say "x = $x"; # x = omega say "y = $y"; # y = alpha
It works every time. The snapshot guarantees the result.

Part 6: ARRAY ELEMENT SWAPS

The same trick works with array elements:
@arr[0, -1] = @arr[-1, 0];
That swaps the first and last elements. Array slices follow the same evaluation rules as list assignment.

You can reverse the first and last three elements of an array like this:

@arr[0, 1, 2, -3, -2, -1] = @arr[-3, -2, -1, 0, 1, 2];
The code looks busy, but it states exactly what it does.

For adjacent swaps inside a loop, which form the core of a bubble sort:

for my $i (0 .. $#arr - 1) { if ($arr[$i] > $arr[$i + 1]) { @arr[$i, $i + 1] = @arr[$i + 1, $i]; } }
No placeholder variable appears anywhere. The list assignment handles the exchange.

Part 7: STRING TRICKS

You can swap words inside a string by combining capture groups with list assignment:
my $str = "hello world"; ($str) = $str =~ s~(\w+)(\s+)(\w+)~$3$2$1~r;
That is a regex approach, but a cleaner list assignment version looks like this:
my ($first, $second) = split /\s+/, $str; ($first, $second) = ($second, $first); $str = "$first $second";
Or you can rebuild the string in one step:
$str = join ' ', reverse split /\s+/, $str;
Different tool, same spirit. Perl gives you several valid options.

Swapping hash keys and values also becomes a one-liner:

my %original = (a => 1, b => 2, c => 3); my %reversed = reverse %original; # %reversed is (1 => 'a', 2 => 'b', 3 => 'c')
The 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:
my ($a, $b) = (0, 1); for (1 .. 20) { say $a; ($a, $b) = ($b, $a + $b); }
Each iteration turns $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:

temp = a a = b b = temp + b
Perl's version reads like the mathematical definition. Two values, one transformation, one line.
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:
sub divide { my ($a, $b) = @_; return (int($a / $b), $a % $b); } my ($quotient, $remainder) = divide(17, 5); say "17 / 5 = $quotient remainder $remainder";
If you want the return values in a different order, you just swap on the receiving end:
my ($remainder, $quotient) = reverse divide(17, 5);
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.

Part 10: UNDER THE HOOD

What does Perl actually do internally when it sees a list assignment? The interpreter follows three steps:
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
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.

This is also why you can safely run:

@array = reverse @array;
Perl does not reverse the array in place and overwrite itself. It builds the reversed list first, then assigns. The old @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.

+---------+ | $temp | +---------+ | [VACANT] | "Position eliminated. Perl doesn't need you." .--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/
perl.gg
✓ Document: Donehidden-gems / 14.8 KiB▧