tags:

views:

395

answers:

9

I am wondering how immutability is defined? If the values aren't exposed as public, so can't be modified, then it's enough?

Can the values be modified inside the type, not by the customer of the type?

Or can one only set them inside a constructor? If so, in the cases of double initialization (using the this keyword on structs, etc) is still ok for immutable types?

How can I guarantee that the type is 100% immutable?

+15  A: 

If the values aren't exposed as public, so can't be modified, then it's enough?

No, because you need read access.

Can the values be modified inside the type, not by the customer of the type?

No, because that's still mutation.

Or can one only set them inside a constructor?

Ding ding ding! With the additional point that immutable types often have methods that construct and return new instances, and also often have extra constructors marked internal specifically for use by those methods.

How can I guarantee that the type is 100% immutable?

In .Net it's tricky to get a guarantee like this, because you can use reflection to modify (mutate) private members.

Joel Coehoorn
Just about covers everything ;-p
Marc Gravell
Hey Marc, I am surprised not to see you on my recent immutable questions. Immutability reminds me of you :)
Joan Venge
+2  A: 

Here is the definition of immutability from Wikipedia (link)

"In object-oriented and functional programming, an immutable object is an object whose state cannot be modified after it is created."

Essentially, once the object is created, none of its properties can be changed. An example is the String class. Once a String object is created it cannot be changed. Any operation done to it actually creates a new String object.

Mr. Will
+1  A: 

I've learned that immutability is when you set everything in the constructor and cannot modify it later on during the lifetime of the object.

Eric
+1  A: 
Lasse V. Karlsen
+1  A: 

An immutable is essentially a class that forces itself to be final from within its own code. Once it is there, nothing can be changed. In my knowledge, things are set in the constructor and then that's it. I don't see how something could be immutable otherwise.

Nathan Lawrence
+3  A: 

Lots of questions there. I'll try to answer each of them individually:

  • "I am wondering how immutability is defined?" - Straight from the Wikipedia page (and a perfectly accurate/concise definition)

    An immutable object is an object whose state cannot be modified after it is created

  • "If the values aren't exposed as public, so can't be modified, then it's enough?" - Not quite. It can't be modified in any way whatsoever, so you've got to insure that methods/functions don't change the state of the object, and if performing operations, always return a new instance.

  • "Can the values be modified inside the type, not by the customer of the type?" - Technically, it can't be modified either inside or by a consumer of the type. In pratice, types such as System.String (a reference type for the matter) exist that can be considered mutable for almost all practical purposes, though not in theory.

  • "Or can one only set them inside a constructor?" - Yes, in theory that's the only place where state (variables) can be set.

  • "If so, in the cases of double initialization (using the this keyword on structs, etc) is still ok for immutable types?" - Yes, that's still perfectly fine, because it's all part of the initialisation (creation) process, and the instance isn't returned until it has finished.

  • "How can I guarantee that the type is 100% immutable?" - The following conditions should insure that. (Someone please point out if I'm missing one.)

    1. Don't expose any variables. They should all be kept private (not even protected is acceptable, since derived classes can then modify state).
    2. Don't allow any instance methods to modify state (variables). This should only be done in the constructor, while methods should create new instances using a particular constructor if they require to return a "modified" object.
    3. All members that are exposed (as read-only) or objects returned by methods must themselves be immutable.

    Note: you can't insure the immutability of derived types, since they can define new variables. This is a reason for marking any type you wan't to make sure it immutable as sealed so that no derived class can be considered to be of your base immutable type anywhere in code.

Hope that helps.

Noldorin
I would add that, if you expose members, they probably should also be immutable...
Denis Troller
@Denis: Yeah, I knew I missed something obvious. Thanks!
Noldorin
Thanks. What if someone wraps my immutable class to make an immutable type? Like say you expose point.X, point.Y for reading and he uses them to reflect/update the changes? Someone told me people even bypass sealed classes.
Joan Venge
@Joan: Using reflection? There's no way to prevent that, I'm afraid. Even the designers of the .NET framework at Microsoft haven't done so. It should however be a clear warning enough that a developer *must* use reflection to modify the state of class, and should really signal that they're doing something hacky. All in all, not a big issue I think.
Noldorin
You are right. I was thinking of a mutable type that is sealed. People could wrap it, but with immutability, I see you only have reflection.
Joan Venge
+5  A: 

The previous posters have already stated that you should assign values to your fields in the constructor and then keep your hands off them. But that is sometimes easier said than done. Let's say that your immutable object exposes a property of the type List<string>. Is that list allowed to change? And if not, how will you control it?

Eric Lippert has written a series of posts in his blog about immutability in C# that you might find interesting: you find the first part here.

Fredrik Mörk
That's an interesting question. Can you make the list readonly?
Joan Venge
That depends on exaclty which type you expose. With a List<T> you can't but if you expose a ReadOnlyCollection<T> you might (I don't know enough about it to claim that it is guaranteed to be readonly). But also regular arrays are mutable, so you really need pay attention to what types you expose in an immutable type.
Fredrik Mörk
Thanks, makes sense.
Joan Venge
+1 for linking Mr. Lippert :P
Lucas
So, is it correct to say that a public readonly property List<T> makes the type mutable?
Gerard
@Gerard: An instance of `List<T>` is *always* mutable. Declaring a `List<T>` variable with `readonly` makes the *variable* read-only, but the variable only contains *the reference to the `List<T>` instance*, not the `List<T>` instance itself (since it is a reference type).
Fredrik Mörk
+4  A: 

One thing that I think might be missed in all these answers is that I think that an object can be considered immutable even if its internal state changes - as long as those internal changes are not visible to the 'client' code.

For example, the System.String class is immutable, but I think it would be permitted to cache the hash code for an instance so the hash is only calculated on the first call to GetHashCode(). Note that as far as I know, the System.String class does not do this, but I think it could and still be considered immutable. Of course any of these changes would have to be handled in a thread-safe manner (in keeping with the non-observable aspect of the changes).

To be honest though, I can't think of many reasons one might want or need this type of 'invisible mutability'.

Michael Burr
Good point Michael.
Joan Venge
An example: splay trees. Internal mutation is used purely to improve performance of lookup, but client code cannot tell that a mutation has taken place (Of course, mutable implementation of splay trees is also possible.)
Norman Ramsey
Compare the C++ keyword "mutable", which designates a class member that can be changed even in a const operation. This is usually for performance reasons, supporting lazy evaluation of something or other.
David Thornley
+1  A: 

There's unfortunately no immutable keywords in c#/vb.net, though it has been debated, but if there's no autoproperties and all fields are declared with the readonly (readonly fields can only bet assigned in the constructor) modfier and that all fields is declared of an immutable type you will have assured your self immutability.

Rune FS