Why are int
s and double
s immutable? What is the purpose of returning a new object each time you want to change the value?
The reason I ask is because I'm making a class: BoundedInt
, which has a value and an upper and lower bound. So I was wondering: should I make this type immutable too? (Or should it be a struct
?)
It makes sense to have
BoundedInt
as a mutable type because it represents a variable that at any point in time has a specific value and that value can be changed but only within a certain range.However integers themselves aren't variables so they should not be mutable.
I'm working on an academic project with Neural Networks. These networks do heavy computation with doubles. I run it on amazon cloud for days on 32 core servers. When profiling the application, the top performance problem is allocation of double!! It would be fair to have a dedicated namespace with mutable types. "unsafe" keywords can be enforced for additional precaution.
Firstly:
I think you might be mistaken about how value types work. This isn't some costly operation like you may be imagining; it's simply the overwriting of data (as opposed to, e.g., dynamic allocation of new memory).
Secondly: here's a very simple example of why numbers are immutable:
Granted, that is a contrived example. So let's consider a couple more involved ideas.
Mutable reference type
First, there's this one: what if
Integer
were a mutable reference type?Then we could have code like this:
And:
This seems to defy intuition: that the line
t2.Integer = t1.Integer
would simply copy a value (actually, it does; but that "value" is in fact a reference) and thus thatt2.Integer
would remain independent oft1.Integer
.Mutable value type
This could be approached another way, of course, keeping
Integer
as a value type but maintaining its mutability:But now let's say we do this:
Basically, immutability of values is something that is highly intuitive. The opposite is highly unintuitive.
I guess that is subjective, though, in all fairness ;)
As a mutable object, you have to lock an
int
variable before you change it (in any multi-threaded code that writes to your int from separate threads).Why? Let's say you were incrementing an
int
, like this:Under the hood, this is a 32-bit number. Theoretically, on a 32 bit computer you could add 1 to it, and this operation might be atomic; that is, it would be accomplished in one step, because it would be accomplished in a CPU register. Unfortunately, it's not; there is more going on than this.
What if another thread mutated this number while it was in the middle of being incremented? Your number would get corrupted.
However, if you make a thread-safe copy of your object before you increment it, operate on your thread-safe copy, and return a new object when your increment is complete, you guarantee that your increment is thread safe; it cannot be affected by any operations on the original object that take place on other threads, because you're no longer working with the original object. In effect, you have made your object immutable.
This is the basic principle behind functional programming; by making objects immutable, and returning new objects from functions, you get thread safety for free.
Anything with value semantics should be immutable in C#.
Mutable classes can't have value semantics because you can't override the assignment operator.
Mutable structs are ugly because you can easily call a mutating method on a temporary variable. In particular properties return temporary variables.
That's why I don't like that most Vector libraries use mutating methods like Normalize in their Vector struct.
Integer variables are mutable. However, integer literals are constants, hence immutable.
It's possible to make an integer field immutable, using
readonly
. Likewise, an integer property could be get-only.