45

I have found that People claim that using all readonly fields in a class does not necessarily make that class's instance immutable because there are "ways" to change the readonly field values even after initialization (construction).

How? What ways?

So my question is when can we really have a "real" immutable object in C#, that I can safely use in threading?

Also do anonymous types create immutable objects? And some say LINQ uses immutable objecst internally. How exactly?

Sathyajith Bhat
  • 21,321
  • 22
  • 95
  • 134
WPF-it
  • 19,625
  • 8
  • 55
  • 71

5 Answers5

106

You've asked like five questions in there. I'll answer the first one:

Having all readonly fields in a class does not necessarily make that class's instance immutable because there are "ways" to change the readonly field values even after construction. How?

Is it possible to change a readonly field after construction?

Yes, if you are sufficiently trusted to break the rules of read-only-ness.

How does that work?

Every bit of user memory in your process is mutable. Conventions like readonly fields might make certain bits appear to be immutable, but if you try hard enough, you can mutate them. For example, you can take an immutable object instance, obtain its address, and change the raw bits directly. Doing so might require a great deal of cleverness and knowledge of the internal implementation details of the memory manager, but somehow the memory manager manages to mutate that memory, so you can too if you try hard enough. You can also use "private reflection" to break various parts of the safety system if you are sufficiently trusted.

By definition, fully trusted code is allowed to break the rules of the safety system. That's what "fully trusted" means. If your fully trusted code chooses to use tools like private reflection or unsafe code to break the memory safety rules, fully trusted code is allowed to do that.

Please don't. Doing so is dangerous and confusing. The memory safety system is designed to make it easier to reason about the correctness of your code; deliberately violating its rules is a bad idea.

So, is "readonly" a lie? Well, suppose I told you that if everyone obeys the rules, everyone gets one slice of cake. Is the cake a lie? That claim is not the claim "you will get a slice of cake". That's the claim that if everyone obeys the rules, you'll get a slice of cake. If someone cheats and takes your slice, no cake for you.

Is a readonly field of a class readonly? Yes but only if everyone obeys the rules. So, readonly fields are not "a lie". The contract is, if everyone obeys the rules of the system then the field is observed to be readonly. If someone breaks the rules, then maybe it isn't. That doesn't make the statement "if everyone obeys the rules, the field is readonly" a lie!

A question you did not ask, but perhaps should have, is whether "readonly" on fields of a struct is a "lie" as well. See Does using public readonly fields for immutable structs work? for some thoughts on that question. Readonly fields on a struct are much more of a lie than readonly fields on a class.

As for the rest of your questions -- I think you'll get better results if you ask one question per question, rather than five questions per question.

Community
  • 1
  • 1
Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 1
    Thx Eric.. ur blog was very useful as well... I got to know this coz I had an interview recently and the interviewer went totally skeptical when I said that readonly fields offer immutability... – WPF-it Jul 17 '11 at 08:41
  • 1
    By extension, `private` fields are also a lie, because they can be accessed in roundabout ways. I'm sure we could all think of other examples. In practice, I'd consider `readonly` fields immutable in most cases because only folly or genius would justify changing a field that is meant to be immutable. I would not consider them immutable in terms of security, because malice brings in a different set of motives and to the attacker what would normally be a stupid bug-prone technique can become a clever means of attack. – Jon Hanna Jul 17 '11 at 16:36
  • 1
    @Jon: Good points; however, if you can mutate a readonly field then your code is already fully trusted, at which point, it doesn't need a clever means of attack. Fully trusted code can just start deleting your files or whatever it is that it wants to do. – Eric Lippert Jul 17 '11 at 19:59
  • @user164184: See also Eric Lippert's [Kinds Of Immutability](http://blogs.msdn.com/b/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx) blog entry, as well as the rest of his [Immutability in C#](http://blogs.msdn.com/b/ericlippert/archive/tags/immutability/) series. `Const` is a particularly interesting case, since the compiler bakes the values into compiled code. – Brian Jul 18 '11 at 20:37
  • Many operating systems, Windows included, offer write protection at page level, which means that "Every bit of memory in your process is mutable" needs to be amended. Do C# programs in particular never have write-protected pages? – Andrei Alexandrescu Jul 21 '11 at 13:41
  • 1
    @Andrei: Is there some mysterious force that stops you from calling VirtualProtect to change the protection to whatever you want before you write it? – Eric Lippert Jul 21 '11 at 13:47
  • ... Today I learned that string too are not immutable -- if you are sufficiently trusted. – Aaron Jul 22 '11 at 05:20
  • One reading this reply my get the *false* impression that readonly field's can't be modified without breaking the rules. Actually, the constructor can modify the field, as well as call any other code; in generally, you have to assume readonly fields can change, because the constructor may have called you, then modified the field after you return. All *without* breaking any rule. – Aaron Jul 22 '11 at 16:44
  • @Aaron: Excellent point. However, note that the original poster specifically said "after construction". Also, it is a bad practice for a ctor to pass "this" to a function and then mutate its state; usually you want the whole object to be initialized to its correct initial state before you call any function. Also note that if a readonly field is initialized with a field initializer, we guarantee that the field has its value before the code in the ctor is called. – Eric Lippert Jul 22 '11 at 17:07
  • A "readonly" declaration on a storage location makes it immutable. That's not a lie--that's what it does. If a constructor stores a reference to an object in a read-only field, it's entirely truthful to say that field will never point to any other object. In many cases, knowing that a field will always point to a particular object is useful information; I don't think it reasonable to refrain from including such information merely because novice programmers who fundamentally do not understand reference types might misinterpret it. – supercat Oct 20 '11 at 22:19
14

EDIT: I've concentrated on code working "within" the system as opposed to using reflection etc as Eric mentions.

It depends on the type of the field. If the field itself is of an immutable type (e.g. String) then that's fine. If it's StringBuilder then the object can appear to change even though the fields themselves don't change their values, because the "embedded" objects can change.

Anonymous types are exactly the same. For example:

var foo = new { Bar = new StringBuilder() };
Console.WriteLine(foo); // { Bar = }
foo.Bar.Append("Hello");
Console.WriteLine(foo); // { Bar = Hello }

So, basically if you have a type that you want to be properly immutable, you need to make sure it only refers to immutable data.

There's also the matter of structs which can have readonly fields but still expose methods which mutate themselves by reassigning this. Such structs behave somewhat strangely depending on the exact situation in which you call them. Not nice - don't do it.

Eric Lippert has written a great deal about immutability - it's all gold, as you'd expect... go read :) (I hadn't noticed that Eric was writing an answer to this question when I wrote this bit. Obviously read his answer too!)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Jon - by saying _Anonymous types are exactly the same_ , do you mean that the actual type is _immutable_ while content _can_ be mutable ? I also saw a similar example when reading the book by ( among others) - yours and Eric. http://books.google.co.il/books?id=s-IH_x6ytuQC&pg=PT65&lpg=PT65&dq=%22readonly+protects+the+location+of+the+field+from+being+changed%22&source=bl&ots=lra68VePaW&sig=NqrwogiRfLlglV8SDmmI0nLuNjE&hl=en&sa=X&ei=EifgUKrmDKnC0AWT24DIBw&redir_esc=y – Royi Namir Dec 30 '12 at 11:35
  • @RoyiNamir: Yes. All anonymous types in C# have read-only properties, but if you create an anonymous type with a `StringBuilder` (for example) there's nothing to stop you from mutating the `StringBuilder` that an instance refers to. – Jon Skeet Dec 30 '12 at 11:39
13

I think Eric's answer is far beyond the scope of the original question, to the point of not even answering it, so I'll take a stab at it:

What is readonly? Well, if we're talking about value types, it's simple: Once the value type is initialized and given a value, it can never change (at least as far as the compiler is concerned).

The confusion starts to set in when we talk about using readonly with reference types. It's at this point we need to distinguish the two components of a reference type:

  • The "reference" (variable, pointer) which points to the address in memory where your object lives
  • The memory that contains the data the reference is pointing to

A reference to an object is itself a value type. When you use readonly with a reference type, you are making the reference to your object immutable, not enforcing immutability on the memory in which the object lives.

Now, consider an object that contains values types and references to other objects, and those objects contain value types and references to other objects. If you were to compose your objects in such a way that all fields in all objects are readonly you can, in essence, achieve the immutability you desire.

w.brian
  • 16,296
  • 14
  • 69
  • 118
  • "making the reference to your object immutable" -- the constructor can modify it, so it's not immutable. See my post. – Aaron Jul 22 '11 at 16:45
  • 3
    True, but I think you're being pedantic. An immutable value needs to come into existence somehow, and that time is during construction. Once the object is constructed, the value is immutable (although it should be said, to appease the pedants, that unsafe code and reflection could still change these immutable values). – w.brian Jul 22 '11 at 21:28
8

Readonly and Thread Safety are two different notions as Eric Lippert explains it.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
0

Perhaps the "People" had heard 3rd hand and communicated poorly about the special privilege that the constructor gets with regards to "readonly" fields. They are not readonly.

Not only that, they're not single-assignment. The constructor for a class can modify the field as many times as it pleases. All without breaking any "rules".

Constructors can also call other arbitrary methods, passing themselves as parameters. So if you're that other method, you can't be certain whether that field is immutable yet, because maybe you were invoked by that object's constructor, and the constructor is going to modify the field as soon as you're done.

You can try it yourself:

using System;
class App
{
    class Foo 
    {
        readonly int x;
        public Foo() {  x = 1; Frob(); x = 2; Frob(); }
        void Frob() { Console.WriteLine(x); }
    }
    static void Main()
    {
        new Foo();
    }
}

This program prints 1, 2. 'x' is modified after Frob read it.

Now, within any single method body, the value has to be constant -- the constructor cannot delegate modify-access to other methods or Delegates, so until a method returns, I'm pretty sure the field will need to remain stable.

All of the above is about classes. Structs are another story entirely.

Aaron
  • 3,454
  • 23
  • 26