Swap two variables without using a temporary variable

Viewed 202431

I'd like to be able to swap two variables without the use of a temporary variable in C#. Can this be done?

decimal startAngle = Convert.ToDecimal(159.9);
decimal stopAngle = Convert.ToDecimal(355.87);

// Swap each:
//   startAngle becomes: 355.87
//   stopAngle becomes: 159.9
29 Answers

The right way to swap two variables (at the time this question was asked(1)) is:

decimal tempDecimal = startAngle;
startAngle = stopAngle;
stopAngle = tempDecimal;

In other words, use a temporary variable.

There you have it. No clever tricks, no maintainers of your code cursing you for decades to come, no entries to The Daily WTF, and no spending too much time trying to figure out why you needed it in one operation anyway since, at the lowest level, even the most complicated language feature is a series of simple operations.

Just a very simple, readable, easy to understand, t = a; a = b; b = t; solution.

In my opinion, developers who try to use tricks to, for example, "swap variables without using a temp" or "Duff's device" are just trying to show how clever they are (and failing miserably).

I liken them to those who read highbrow books solely for the purpose of seeming more interesting at parties (as opposed to expanding your horizons).

Solutions where you add and subtract, or the XOR-based ones, are less readable and most likely slower than a simple "temp variable" solution (arithmetic/boolean-ops instead of plain moves at an assembly level).

Do yourself, and others, a service by writing good quality readable code.

That's my rant. Thanks for listening :-)

As an aside, I'm quite aware this doesn't answer your specific question (and I'll apologise for that) but there's plenty of precedent on SO where people have asked how to do something and the correct answer is "Don't do it".


(1) Improvements to the language and/or .NET Core since that time have adopted the "Pythonic" way using tuples. Now you can just do:

(startAngle, stopAngle) = (stopAngle, startAngle);

to swap values.

First of all, swapping without a temporary variable in a language as C# is a very bad idea.

But for the sake of answer, you can use this code:

startAngle = startAngle + stopAngle;
stopAngle = startAngle - stopAngle;
startAngle = startAngle - stopAngle;

Problems can however occur with rounding off if the two numbers differ largely. This is due to the nature of floating point numbers.

If you want to hide the temporary variable, you can use a utility method:

public static class Foo {

    public static void Swap<T> (ref T lhs, ref T rhs) {
        T temp = lhs;
        lhs = rhs;
        rhs = temp;
    }
}

Yes, use this code:

stopAngle = Convert.ToDecimal(159.9);
startAngle = Convert.ToDecimal(355.87);

The problem is harder for arbitrary values. :-)

int a = 4, b = 6;
a ^= b ^= a ^= b;

Works for all types including strings and floats.

Not in C#. In native code you might be able to use the triple-XOR swap trick, but not in a high level type-safe language. (Anyway, I've heard that the XOR trick actually ends up being slower than using a temporary variable in many common CPU architectures.)

You should just use a temporary variable. There's no reason you can't use one; it's not like there's a limited supply.

In C# 7:

(startAngle, stopAngle) = (stopAngle, startAngle);

<deprecated>

You can do it in 3 lines using basic math - in my example I used multiplication, but simple addition would work also.

float startAngle = 159.9F;
float stopAngle = 355.87F;

startAngle = startAngle * stopAngle;
stopAngle = startAngle / stopAngle;
startAngle = startAngle / stopAngle;

Edit: As noted in the comments, this wouldn't work if y = 0 as it would generate a divide by zero error which I hadn't considered. So the +/- solution alternatively presented would be the best way to go.

</deprecated>


To keep my code immediately comprehensible, I'd be more likely to do something like this. [Always think about the poor guy that's gonna have to maintain your code]:

static bool Swap<T>(ref T x, ref T y)
{
    try
    {
        T t = y;
        y = x;
        x = t;
        return true;
    }
    catch
    {
        return false;
    }
}

And then you can do it in one line of code:

float startAngle = 159.9F
float stopAngle = 355.87F
Swap<float>(ref startAngle, ref stopAngle);

Or...

MyObject obj1 = new MyObject("object1");
MyObject obj2 = new MyObject("object2");
Swap<MyObject>(ref obj1, ref obj2);

Done like dinner...you can now pass in any type of object and switch them around...

For completeness, here is the binary XOR swap:

int x = 42;
int y = 51236;
x ^= y;
y ^= x;
x ^= y;

This works for all atomic objects/references, as it deals directly with the bytes, but may require an unsafe context to work on decimals or, if you're feeling really twisted, pointers. And it may be slower than a temp variable in some circumstances as well.

a = a + b
b = a - b
a = a - b

َ

For binary types you can use this funky trick:

a %= b %= a %= b;

As long as a and b are not the exact same variable (e.g. aliases for the same memory) it works.

Sometimes I wish it were possible to write a function in MSIL inline in C#, similar to how you can write inline assembler in C.

For the record, I once wrote a helper library for C# with various functions for things that were impossible to write in C# but can be written in MSIL (non-zero-based arrays for example). I had this function:

.method public hidebysig static void Swap<T> (
        !!T& a,
        !!T& b
    ) cil managed 
{
    .maxstack 4

    ldarg.1      // push a& reference
    ldarg.2      // push b& reference
    ldobj !!T    // pop b&, push b
    ldarg.2      // push b& reference
    ldarg.1      // push a& reference
    ldobj !!T    // pop a&, push a
    stobj !!T    // store a in b&
    stobj !!T    // store b in a&
    ret
}

And no locals needed. Of course this was just me being silly...

this model is very useful

        var a = 10;
        var b = 20;

        (int a,int b)  c = (a,b);

        a = c.b ;
        b = c.a ;
Related