views:

252

answers:

2

In .NET 4 beta 2, there is the new Numerics namespace with struct BigInteger. The documentation states that it is an immutable type, as I would have expected.

But I'm a little confused by the post-increment operator (++). This defintely seems to mutate the value. The following while-loop works:

static BigInteger Factorial(BigInteger n)
{
    BigInteger result = BigInteger.One;
    BigInteger b = BigInteger.One;

    while (b <= n)
    {
        result = result * b;
        b++;  // immutable ?
    }
    return result;
}

This is what MSDN has to say about the Increment operator:

Because BigInteger objects are immutable, the Increment operator creates a new BigInteger object whose value is one more than the BigInteger object represented by value. Therefore, repeated calls to Increment may be expensive.

All well and fine, I would have understood if I had to use b = b++ but apparently ++ by itself is enough to change a value.

Any thoughts?

Edit:
As Lasse points out, there is a step-by-step specification for how post-increment works. But this still seems att odds with immutability. For instance, I can't imagine that using this operator is thread-safe.

+6  A: 

The operators ++ and -- are implemented in terms of the normal + and - operators, so in reality:

b++;

is equivalent to:

var temp = b;
b = b + 1;
<use temp for the expression where b++ was located>

Now, as commented, this might seem like it breaks immutability, but it does not.

You should instead look at this code as doing this:

var temp = b;
b = BigInteger.op_Add(b, 1); // constructs a new BigInteger value
<use temp ...>

This will leave two objects in memory, the original BigInteger value, and the new one, now referenced by b. You can easily check that this is what happens with the following code:

var x = b;
b++;
// now inspect the contents of x and b, and you'll notice that they differ

So the original object did not change, hence it does not break immutability, and to answer the new part of the question, this should be thread-safe.

This is the same thing that happens to strings:

String s1 = s2;
s2 += "More";
// now inspect s1 and s2, they will differ
Lasse V. Karlsen
Sounds reasonable, but it still seems break the immutability. I'll edit the question a little.
Henk Holterman
No, it doesn't break immutability, let me update my answer.
Lasse V. Karlsen
In `s+= s2` there is a visible assignment. It fits if you accept that `b++` is also an assignment, ie `b = b + 1`. But `++` still feels/looks like it's mutating.
Henk Holterman
+3  A: 

Since BigInteger is immutable, b++ will be just equivalent to:

BigInteger temp=b;
b=temp+1;

After this operation, temp is recycled by the GC and the memory is freed.

Ted Lee
OK, except for the GC part. It's a struct (with an internal array).
Henk Holterman
Yes, and the only difference is that struct is stored on stack while this class is stored in the heap.
Ted Lee
Ted, where do you think a BigInteger field in an object is stored?
Henk Holterman
It's in the heap, with a reference to it stored on the stack.
Ted Lee