Sdílet prostřednictvím


Immutability in C# Part One: Kinds of Immutability

I said in an earlier post that I believe that immutable objects are the way of the future in C#. I stand by that statement while at the same time noting that it is at this point sufficiently vague as to be practically meaningless! “Immutable” means different things to different people; different kinds of immutability have different pros and cons. I’d like to spend some time over the next few weeks talking about possible directions that C# could go to improve the developer experience when writing programs that use immutable objects, as well as giving some practical examples of the sort of immutable object programming you can do today.

(Again, I want to emphasize that in these sorts of “future feature” posts we are all playfully hypothesizing and brainstorming about ideas for entirely hypothetical future versions of C#. We have not yet shipped C# 3.0 and have not announced that there will ever be any future version of the language. Nothing here should be construed as any kind of promise or announcement; we’re just geeks talking about programming languages, ‘cause that’s what we do.)

So, disclaimers out of the way, what kinds of immutability are there? Lots. Here’s just a few. Note that these categories are not necessarily mutually exclusive!

Realio-trulio immutability:

There’s nothing you can do to the number one that changes it. You cannot paint it purple (‡), make it even or get it angry. It’s the number one, it is eternal, implacable and unchanging. Attempting to do something to it – say, adding three to it – doesn’t change the number one at all. Rather, it produces an entirely different and also immutable number. If you cast it to a double, you don’t change the integer one; rather, you get a brand new double.

Strings, numbers and the null value are all truly immutable.

C# allows you to declare truly immutable named fields with the const keyword. The compiler ensures that the only things that are allowed to go into const fields are truly immutable things – numbers, strings, null. (See the section of the standard on “constant expressions” for details.)

Write-once immutability:

Fields marked as const have to be compile-time constants, which is a bit of a pain if what you want to do is have a field which never changes but nevertheless cannot be computed until runtime. For example, in a later post I’m going to define an immutable stack class which has this code:

public sealed class Stack<T> : IStack<T>
{
private sealed class EmptyStack : IStack<T>
{ /* ... */ }
private static readonly EmptyStack empty = new EmptyStack();
public static IStack<T> Empty { get { return empty; } }

I will want to create a singleton empty stack. Clearly it is not a compile-time constant, so I cannot make the field const. But I want to say “once this thing is initialized it is never going to change again.” That’s what the readonly modifier ensures. Basically it’s a “write only once” field. Not exactly immutable, since obviously it changes exactly once, from null to having a value. But pretty darn immutable.

Popsicle immutability:

...is what I whimsically call a slight weakening of write-once immutability. One could imagine an object or a field which remained mutable for a little while during its initialization, and then got “frozen” forever. This kind of immutability is particularly useful for immutable objects which circularly reference each other, or immutable objects which have been serialized to disk and upon deserialization need to be “fluid” until the entire deserialization process is done, at which point all the objects may be frozen.

There is at present no really universal convention for how to declare a freezable object, and there certainly is no support in the compiler for this kind of immutability.

Shallow vs deep immutability:

Consider a write-once field containing an array:

public class C {
private static readonly int[] ints = new int[] { 1, 2, 3 };
public static int[] Ints { get { return ints; } }

The value of the field cannot be changed; C.ints = null; would be illegal even from inside the class. This is a sort of “referential” immutability. But there is nothing immutable at all about the array itself! C.Ints[1] = 100; is still perfectly legal from outside the class.

The ints field is “shallowly” immutable. You can rely upon it being immutable to a certain extent, but once you reach a point where there is a reference to a mutable object, all bets are off.

Obviously the opposite of shallow immutability is “deep” immutability; in a deeply immutable object it is immutable all the way down.

If we had immutability in the type system, something like the far stronger kind of “const” in C/C++, then a hypothetical future compiler could verify that an object marked as deeply immutable had only deeply immutable fields.

Objects which are truly madly deeply immutable have a lot of great properties. They are 100% threadsafe, for example, since obviously there will be no conflicts between readers and (non-existant) writers. They are easier to reason about than objects which can change. But their strict requirements may be more than we need, or more than is practical to achieve.

Immutable facades:

Since the contents of an array (though, interestingly enough, not its size) may be changed arbitrarily, it’s a bad idea to expose data that you want to be logically read-only in a public array field. To make this a bit easier, the base class library lets you say

public class C {
private static readonly intarray = new int[] { 1, 2, 3 };
public static readonly ReadOnlyCollection<int> ints = new ReadOnlyCollection<int>(intarray);
public static ReadOnlyCollection<int> Ints { get { return ints; } }

The read-only collection has the interface of a regular collection; it just throws an exception every time a method which would modify the collection is called. However, clearly the underlying collection is still mutable. Code inside C could mutate the array members.

Another down side of this kind of immutability is that the compiler is unable to detect attempts to modify the collection. Attempts to, say, add new members to the collection will fail at runtime, not at compile time.

This sort of immutability is a special case of...

Observational immutability:

Suppose you’ve got an object which has the property that every time you call a method on it, look at a field, etc, you get the same result. From the point of view of the caller such an object would be immutable. However you could imagine that behind the scenes the object was doing lazy initialization, memoizing results of function calls in a hash table, etc. The “guts” of the object might be entirely mutable.

What does it matter? Truly deeply immutable objects never change their internal state at all, and are therefore inherently threadsafe. An object which is mutable behind the scenes might still need to have complicated threading code in order to protect its internal mutable state from corruption should the object be called on two threads “at the same time”.

Summing up:

Holy goodness, this is complicated! And we have just barely touched upon the deeply complex relationship between immutability of objects and “purity” of methods, which opens up huge cans of worms.

So, smart people, what do you think? Are there forms of immutability which I did not touch upon here that you like to take advantage of in your programs? Are there any particular forms of immutability which you would like to see made easier to use in C#?

Next time: let’s get a little more practical. I already implemented an immutable stack in my A* series, but that was pretty special-purpose. We’ll take a look at how one might implement a general-purpose immutable stack today in C# 3.0. We'll then expand that to immutable queues, trees, etc. (And I might even discuss how one could take advantage of typesafe covariance when designing interfaces for immutable data structures, oh frabjous day!)

(‡) A dear old friend of mine from school who happens to be a grapheme-colour synaesthete tells me that of course you cannot paint the number one purple because it is already blue. Silly me!

Comments

  • Anonymous
    November 13, 2007
    JayBaz and I have thought about "Popsicle Immutability" quite a lot.  We decided that having two different forms of a type helped out here.  A mutable "Builder" class, and then an immutable version.  so you might have a class like: class Immutable {    public class Builder {        public int Prop { get; set; }        public Immutable Realize() { return new Immutable(this.Prop); }    }    readonly int _prop;    public int Prop { get { return this._prop; } }    public Immutable(int prop)    {        this._prop = prop;    } } Jay even went so far as to implement a code generator that would generate the two class using CodeDom I think.

  • Anonymous
    November 13, 2007
    Eric, if you and Joe Duffy haven't been talking to each other, you really should do. (I'd pay to hear good money that conversation, too - on practically any topic about C# or concurrency.) From a couple of days ago: http://www.bluebytesoftware.com/blog/2007/11/11/ImmutableTypesForC.aspx Also, I'd claim that String actually is only observationally immutable. StringBuilder manages to mutate it with no problems - it just makes sure that it never mutates a string which has already been publicised. At least, that's my understanding. Jon

  • Anonymous
    November 13, 2007
    Though of course I have been seeing email from him for years, I actually just met Joe for the first time a few days ago, coincidentally enough at a meeting where we were discussing immutability in C#/CLR.   I had no idea he was blogging about the same thing, thanks for pointing this out.

  • Anonymous
    November 13, 2007
    And regarding strings -- yes, you are right, I had not considered the magic that StringBuilder does behind the scenes. And indeed, there is all kinds of threading logic in a string builder to ensure that the actually-mutable underlying state of the string is always threadsafe and never observable by the caller.

  • Anonymous
    November 13, 2007
    The comment has been removed

  • Anonymous
    November 13, 2007
    I've, ahem, somehow managed to see some possible C# code for the string.Join method (how in the world could that have happened?).  A string is accessed by address after being pinned and written to directly.  This is completely acceptable, as there is no way for multiple threads to access the same mutating string; once it's out into the brutal, multithreaded world, it is immutable.  This is popsicle immutability.  Perhaps it would be possible to establish the freezing point and then have the compiler (or some tool) verify that pre-frozen code is thread-safe (or, at least make some guarantee). One type, or perhaps usage of immutability would be to specify that a given variable (or parameter, field) isn't to be changed.  The discussion I have seen about this issue is that it isn't really worth it, that C++-style const functions and arguments ended up being a royal pain.  However, it seems to me that the excellent tooling support wouldn't be too hard to provide, so that you could propagate constness easily.  It would be pretty cool to be able to analyze code and show what objects are being modified where (this can be done) -- with const-support, one could show which objects are allowed to be modified where.

  • Anonymous
    November 13, 2007
    The comment has been removed

  • Anonymous
    November 13, 2007
    The fact that ReadOnlyCollection<T> enforces its immutability at runtime rather than compile-time is just a detail of this class, not a general principle of Immutable Facades.  I would argue that Immutable Facades should generally be written to enforce immutability at compile-time.

  • Anonymous
    November 13, 2007
    The comment has been removed

  • Anonymous
    November 13, 2007
    something java has and which I quite like is immutability of local variables. In one case they make it quite clear and compile checked that it is written to once in the method call (I know the JIT doesn't need the hint to optimize the enregistration process itself) They allow closures to be more effectively controlled (though in theory static analysis can do this too) so that a more complex case can be made more simple (as they are effectively used in java where you must apply the keyword to make use of local variables in the limited closures provided) As a side note the variable created by foreach is a form of immutability...

  • Anonymous
    November 14, 2007
    The comment has been removed

  • Anonymous
    November 14, 2007
    The only other type of immutability in my mind would be "variant immutablility" where the object is immutable to some actors, but totally mutable to others.  Something like the C++ friend declaration, but with limitations on what operations (read/write) can be performed on which member variables by which "friends".

  • Anonymous
    November 14, 2007
    re: Immutable facades I agree with mharder (and Stefan) here.  Given that both C# and Java do it this way (wrapper classes that enforce immutability at run-time), is there a reason that providing e.g. IConstList and IList : IConstList is more difficult than it seems?

  • Anonymous
    November 15, 2007
    The comment has been removed

  • Anonymous
    November 15, 2007
    But doesn't const have to be infectious or it loses its power? The reason it gets ugly in C/C++ codebases is there there is lots of legacy code which was pretty loosey-goosey with const-correctness. Because it's possible to cast-away constness in C/C++, people often choose that as the solution to interfacing with these codebases. (Hey, it makes the compiler stop complaining, right?) With C# and the .Net framework, there was an opportunity to build robust concepts of immutability right into the foundations from the get-go. I now fear that this opportunity has been lost and there is too much code out there already (notably the existing framework classes) that new code will have to interface with.

  • Anonymous
    November 15, 2007
    mccoyn, the key is to derive IList from IReadOnlyList, not the other way around. Guessing const-ness of parameters would be an invitation for unintentional breaking changes. Unfortunately, like MGSPDevB just said, const needs to be infectious to bring any real value. However, compared to C++, I believe the problem there was that it didn't pull its own weight. It was created to find bugs at compile time, but in real life it just found const-ness errors. However, in a system that can enforce const-ness for security reasons, this in itself would be a value. ("Casting away constness" by casting an IReadOnlyList to an IList is nothing that could be prevented by CAS though) Making it usable in parallel scenarios would be an additional goodie. The question is, how much does it have to affect existing code, or how easy is it to ignore const-ness and just get on with it. Modifying the BCL to specify const-ness of parameters is certainly possible, and for input parameters if really affects no one. However, changing output parameters/returns to const would have an effect that MS is certainly not going to tolerate (unless they introduce somthing like Option Ignore Const, which is totally not C#)

  • Anonymous
    November 15, 2007
    What was the story with Spec#? It's been a while I looked but  I remember vaguely that you could constrain sizes of stuff etc. throughout method invocations. Sounds like some sort of immutability. Could you not express immutability concerns with the concept of Spec#?

  • Anonymous
    November 16, 2007
    I love immutable types. The trouble is, I also love object initialization syntax. If there were a way those two could play nicely, I would be elated.

  • Anonymous
    November 19, 2007
    I'm concerning about two things. One is overhead of creation of immutable object. Whatif objects are created masively which that the way in real-life usage.right? The other is GC. if everything go immutable, Is GC will does the collecting up oftenly which is led to performance problem? How can we handle this issues?

  • Anonymous
    November 20, 2007
    A bunch of people ( Eric , Wes , Joe , etc) have been writing about the wonders of immutable data structures

  • Anonymous
    November 20, 2007
    A bunch of people ( Eric , Wes , Joe , etc) have been writing about the wonders of immutable data structures

  • Anonymous
    December 12, 2007
    Even "deeply" immutable objects are NOT necessarily 100% thread-safe (or at least their methods aren't), because the methods might rely on non-immutable properties from their arguments. The only way around this is to require all method arguments on deep-immutable objects to be at minimum observationally immutable.

  • Anonymous
    December 12, 2007
    Right, that's what I meant when I said that the relationship between functional purity and immutability opens up interesting cans of worms.

  • Anonymous
    December 12, 2007
    The comment has been removed

  • Anonymous
    December 12, 2007
    I was hoping to find intentions to support readonly also on local Variables and Parameters. This is possible in Java using the "final" Keyword and it keeps a lot of hassle from less experienced Programmers, because it prevents them from changing the Value of once-initialized Variables, which is one of the most frequent Reason for bugs, according to "Code Complete" by Steve McConnell. I would go even further and make EACH Variable readonly and use a new Keyword like e.g. "writable" to indicate mutable Variables. In Fact the only really useful mutable Variables are indices and Accumulators in Loops, so these should implicitly be mutable: double sum; for(int i = arr.length; --i >= 0;) sum+=arr[i];

  • Anonymous
    December 12, 2007
    An object which represent a data model (like an Abstract Syntax Tree), may be passed to n number of consumers in a program. All the comsumers are supposed to do is use the model for calculations; not to modify it. In this scenario, If I could say that the object itself is readonly, it can preven anybody from altering the contenets of it. Wont that be a nice feature a language should have. (I know that I can clone the object to prevent the changes from reflecting back or use a state pattern to allow/disallow changes; but will affect other aspects of my program)

  • Anonymous
    December 13, 2007
    @Eric, I get that you understand the complexity involved, but I was just responding to your comment that "[o]bjects which are truly madly deeply immutable...are 100% threadsafe...", which is not strictly true (depending on your definition of madly), and might be confusing to some.

  • Anonymous
    December 17, 2007
    Seasonal immutability: The idea is like Popsicle, but occasionally, you thaw it out to change its data, then re-freeze it.  I have a lot of cases where I have shared data that is const, but every once in a while I need to publish a change to that data.  That means my accessors have to implement some type of reader/writer lock even though days can go by with no change.  I don’t know what if anything the compiler could do to help though.

  • Anonymous
    December 18, 2007
    There might be another angle on this.  As you said, if you cast the integer one to a double you get a new double with a value of 1.  The old integer 1 is still an integer 1 and acts like the integer 1.  The new double, while conceptually equal to the old integer 1 it is derived by and operated on by different rules.  int i=5;i/=4; is also (integer) 1, but double d=5;d/=4; it is not (double) 1. We have to consider a version of immutability that includes the context it is being using in (which override or new functions) and the lambda expression values on static members in the class at the time. Our another way to think of it is instead of a declarative expression ( int i = 1; ) or a functional expression ( return new Int32(1); )   we need a nominative expression ( enum { One=(int)1 }  ) declaring that we want to call this class with all of its values in its current state by the name "One".   Just like the integer before, the class is still open to be changed.   i++;    But it will no longer be One.

  • Anonymous
    December 18, 2007
    I'm not sure the above says what I meant it to. What I meant is that I'd like to see a tag in the enum style to create an immutable object.  It's up to the compiler to decide if it has enough to resolve at compile or run-time. (MSVS does a pretty good job of partially building objects up enough to display them in the designer.) Call it an Alias, Signature, Snapshot, Tag, or whatever you think a class object level naming expression needs to be named. The idea is: //new object, value resolves as (int) 1 FunkyIntType intlikeOne = new FunkyIntType((int)1); //new object, value resolves as (double) 1 FunkyIntType doublelikeOne = new FunkyIntType((double)1); Alias One = { (int)1, (double)1, new funkyIntType((int)1), doublelikeOne }; int i=One;    //new Int32( (Int32)One )  returns either One[0] or One[2], most likely One[0] for(;i<One7;i++) ...   //again, since i is int, One is first Aliased typeof(int), or nearest context'd typeof(int) double d=One; for(;d<One22;d++) ... doublelikeOne.divideOp=intlikeOne.divideOp; if (doublelikeOne is One)  ...   //this is indeterminate unless immutable tag types above are declared, strictly speaking on object in One is a snapshot of the current doublelikeOne, even though One[1] and One[3] resolve to the same thing. // new context {       //new object, value resolves as (double) 1     FunkyIntType exprlikeOne = new FunkyIntType( () => 5/4 );       exprlikeOne.methods[arithmetic] = int.methods[arithmetic];    //Add to previous aliases from here to end of block     Alias One {  (int)new FunkyIntType( () => 5/4, int.methods[arithmetic]  ),       exprlikeOne    };     // compiler created the first object, resolved it and threw it away after the expression was finished     // but second inclusion is a lambda expression that creates a copy of this exprlikeOne snapshot in     // this current state if it is referenced later    if (   new FunkyIntType( () => 5/4 , int.methods[arithmetic] ) == One  ) ...        //this is true    if (   exprlikeOne == One  ) ...        //this is true     exprlikeOne.methods[arithmetic] = double.methods[arithmetic];    if (   new FunkyIntType( () => 5/4, int.methods[arithmetic] ) == One  ) ...        //this is true    if (   exprlikeOne == One  ) ...        //this is false, because this is the same as  (   ( (double)5/4 ) == One  ) } if (   new FunkyIntType( () => 5/4 ) == One  ) ...     //this is indeterminate unless immutable tag types above are declared, // i.e. do we do conversion against each type Aliased or not

  • Anonymous
    December 18, 2007
    Ok, quick fix and I'll stop.  (assume there are other errors too) // new context {      //new object, value resolves as (double) 5/4 (until methods changed)   <= not (double)1  

  • Anonymous
    December 18, 2007
    Ok. so one more... I mentioned I'd like it in enum style, but then went on and showed it as a declarative (which I'd still want). So here's a supplement: Alias MyMetric as increment ( (x) =>x+1 ) { One = { (int)1, (double)1, new funkyIntType((int)1), doublelikeOne }, Two,  //  :== { ((int)1)+1, ((double)1)+1, (new funkyIntType((int)1))+1, (doublelikeOne)+1 }, OutOfRange= (x)=>(x!=One && x!=Two) }; { // new context   // hmm, two is not valid anymore, at least for this context   MyMetric-=Two; }

  • Anonymous
    December 18, 2007
    Just isn't my day.  Not nominative expression... Vocative expression.

  • Anonymous
    December 20, 2007
    Something bothering me about my Dec 18, 1:21PM post. Concerning: "OutOfRange= (x)=>(x!=One && x!=Two)" x!=Two when Two is undefined in the new context should be an error. Throw that out.  It'd be enough if all Aliases support the bool Exists(x) method.   Maybe this is turning into an immutable object container... I suppose that works too.   It's just that when I think immutable objects I immediately think named collections of properties. When I think collections of properties I include function pointers and lambda expressions. When I think lambda expressions I think algorithms. When I think algorithms I think limits, summations, and other equations used in calculus and logic proofs, relational algebra, et al. When I think algorithms I also think of abstract, not real until used, collections of objects. (Two does not exist, but One does, Two is the state of One after being added to One, If I reference the name Two, then I need to find a One and add it to a One right then and there.  That does not mean that Two is not an immutable object.) So naturally I think of algorithms as parts or wholes of immutable objects.

  • Anonymous
    January 02, 2008
    The/an extension of the "popsicle immutability" concept seems interesting to me. Imagine the "mutability status" of an object being subject to a parameter, called "temperature". As you increase the temperature of the object, it becomes more mutable; as the object's temperature decreases, it becomes less mutable. This would form the basis for creating "optimal objects" through a simulated annealing process. No, I can't offhand think of any glamourous applications of this concept; it just struck me as interesting.

  • Anonymous
    January 08, 2008
    I've been reading Eric Lippert's series on immutable collections (start here with part one ) over on

  • Anonymous
    January 09, 2008
    There have been some talks suggesting Microsoft to stop developing C# and simply move on to a...

  • Anonymous
    January 10, 2008
    It seems all of the add-on functions suggested for C# come back to a lack of theading support that isn't built in by the programmer.  This is has been true for any language.  It would seem a lot easier to just declare classes that are tread safe ThreadSafe.   For classes not marked the complier knows to knows it has to keep thread locked calls and synced copy (if another is created on a second thread).  Probably a big performance hit for existing code, but a lot less crashes.

  • Anonymous
    January 12, 2008
    There is a powerful and simple concept in programming that I think is really underused: Immutability

  • Anonymous
    January 16, 2008
    For some reason, there's been a lot of buzz lately around immutability in C#. If you're interested in

  • Anonymous
    January 23, 2008
    I've been following this series but still don't know the why of wanting Immutability? What would a practicial business implementation be and why would it be beneficial?

  • Anonymous
    January 23, 2008
    Read part nine.

  • Anonymous
    January 26, 2008
    In SharpDevelop 1.1, the IClass interface had a property that was used in several places in the code

  • Anonymous
    February 07, 2008
    Microsoft haven&#39;t committed to anything in C# 4 yet. However, there have been hints about what they&#39;ve

  • Anonymous
    February 13, 2008
    I have just been doing some work building a very long (2-10kb) string character by charater. The book I referrred to said use stringbuilder not strings. The problem with strings is that they are immutable so each time I add a chatacter the string gets copied. It is slow, inefficient and not what most developers want or need. Microsoft gives us immutable strings but also has to give us something that performs. My view is that Microsoft people need to stop presenting us with theoretically good ideas unless they are- simple to use, make developing faster, easier to understand and perform well in the real world. Immutability- If I need it I want it. If I dont need it then I dont want it and would rather not be forced to use it.

  • Anonymous
    February 13, 2008
    I certainly take your larger point to heart -- which, I might paraphrase as "good design is the art of compromising between conflicting goals, so please find out what my needs are and prioritize them".  This is certainly what we try to do every day: figure out our customers' needs, and choose designs which prioritize them. However, I feel compelled to point out that your smaller point is a non sequitur.  The problem with string concatenation being expensive has practically nothing to do with the fact that strings are immutable. Rather, it is a consequence of two things. First, that strings are fixed length, and second, that they are implemented as contiguous memory buffers. That gives us three ways to attack the problem. The first would be to make strings into non-fixed length mutable structures that use a double-when-full strategy.  That makes string concatenation O(1) on average, but it also means that s1 = "hello" s2 = s1 + "goodbye" would either (a) change the value stored in s1, or (2) copy the value stored in s1, and hey, guess what, we're back to an inefficient concatenation algorithm again. I hope that you would reject both of these options. The second would be to make the underlying implementation of trees into, say, the immutable deque I developed in part eleven of this series. This gives cheap concatenation at the expense of making it immensely expensive to interrogate the interior of the string. I hope you would reject this too.  Favouring one common operation at the massive expense of another is a bad balancing of competing goals if that massive expense cannot be avoided by other means. I once spent an entire summer rewriting the VBScript string library to use immutable trees instead of immutable BSTRs. It was a disaster. The performance overhead of maintaining the trees was immense compared to the tiny savings of making pages that did a million concatenations faster. The third approach would be to keep the good performance and value-like semantics by using an underlying implementation that uses immutable fixed-size character arrays, and addressing the quadratic nature of the concatenation operator by providing a highly efficient and well-tuned alternative. Some sort of "string builder" class, you might say. Design is, as I said, the art of compromising. Implementing strings as immutable character arrays is the best choice that balances out all these competing design goals; had we picked something else, you'd be complaining MORE about it. That there is no perfect solution to this problem is a fact about the nature of computation, not about our inability to make good design choices. The point of this whole series is that programming in C# using immutable data structures is:

  • simpler to use than mutable data structures for many use cases

  • far easier to reason about than mutable structures

  • make development faster by reducing the amount of time tracking down mutation bugs or reasoning about mutation semantics

  • trade off understandability, robustness, and applicability in rich scenarios against performance of memory allocation, which is typically cheap and fast anyway. Is it a panacea? No. Should you be forced to use it? Of course not. Is it an incredibly valuable tool that you should have in your toolbox, sharp and ready for use? Yes. Should you be able to understand it when other people use it?  Oh my yes, you will see a lot more coding in this style in C# in the future, I predict.

  • Anonymous
    March 11, 2008
    Okay, I know I said that part 4 would be the last part in this series ... but since then I&#39;ve not

  • Anonymous
    April 01, 2008
    This is really a good article. Thnkx for telling about immutable objects

  • Anonymous
    May 21, 2008
    C#中的不变类型 ThereisapowerfulandsimpleconceptinprogrammingthatIthinkisreallyunderused:...

  • Anonymous
    July 07, 2008
    I've been reading Eric Lippert's series on immutable collections (start here with part one ) over on his blog, Fabulous Adventures in Coding . I don't understand everything he writes, but it's still a fascinating read. This morning on my commute I was

  • Anonymous
    August 18, 2008
    Another very simple pattern builds on the foundation of the Safe-Unsafe Cache pattern .&#160; What is

  • Anonymous
    August 20, 2008
    My port of the Protocol Buffers project has proved pretty interesting. I thought I&#39;d share some of

  • Anonymous
    September 01, 2008
    Hi! I've been looking around for a simple example of the "right way" to implement immutable object xml serialization/deserialization. Since IXmlSerializable.ReadXml(System.Xml.XmlReader reader) requires the object inner state to be changed, I have to make private fields writable, which I would like to avoid. I've tried googling it but was unable to find the answer I was looking for. Thanks a lot, Veki

  • Anonymous
    October 25, 2012
    How to implement Array Immutability in C#? wisentechnologies.com/.../.net-training.aspx