Thanks a lot for your great feedback!
Two months ago, we shipped a NuGet package with support for immutable collections. We’ve also talked about it on Channel 9. Since then we received feedback through various channels and we’re happy to announce we shipped an update on NuGet that addresses your feedback.
Feedback Channels
First of all: how are we tracking your feedback? We track social media, such as Twitter, Reddit and our official Facebook page. We also track StackOverflow, Connect, the comments on this blog, and last but not least emails send through the NuGet’s Contact Owners mechanism. Yes, we really want your feedback!
The most direct way to contact us is via NuGet or comments on this blog.
Your Feedback
Package Installation Issues
Some customers reported issues with installing the NuGet package. In all cases, the root cause was an outdated version of the NuGet package manager. Immutable collections use portable class libraries and they are only supported by NuGet 2.1 or higher.
In order to update the immutable collections package, please install the latest version of NuGet. You can check whether you have the latest version by going to Tools | Extensions and Updates. When the Extensions and Updates dialog opens, select Updates | Visual Studio Gallery and look for an entry titled NuGet Package Manager.
Unfortunately, there is currently no way for a package to specify a minimum required version of NuGet. To address this in the future, we have worked with the NuGet team and NuGet 2.3 will add this ability. For now, you will need to know to install an updated version of NuGet.
Construction
We explicitly decided not to provide constructors for immutable collections. The reason for this is that immutable collections typically start with an empty instance. Since all empty instances would be the same, this would result in a lot of wasted objects. Instead, we decided to use a singleton as the empty instance.
Unfortunately this decision resulted in quite verbose code:
var list = ImmutableList.Empty.Add(1, 2, 3);
Furthermore, this approach doesn’t support type inference as the generic arguments must be specified. Besides having to type more this also means that anonymous types aren’t supported (remember: only Jon Skeet knows their names).
We’ve fixed this by using a solution similar to what we use for Tuple. We’ve created non-generic types that serve as a factory for creating immutable collections. Also, we’ve removed the Empty property and replaced it by a factory method (it still returns a singleton but this makes the design more consistent).
This allows you to write code like this:
var anEmptyList = ImmutableList.Create(); var oneTwoThree = ImmutableList.Create (1, 2, 3);
which can be shortened as it allows for type inference:
var oneTwoThree = ImmutableList.Create(1, 2, 3);
which in turn enables anonymous types:
var andrew = new { FirstName = “Andrew”, LastName = “Arnott” }; var matt = new { FirstName = “Matt”, LastName = “Cohn” }; var immo = new { FirstName = “Immo”, LastName = “Landwerth” }; var list = ImmutableList.Create(andrew, matt, immo);
Interoperating with existing collections
As you are probably aware, the existing mutable collection interfaces in the BCL support the notion of read-only-ness. In our original design we made the decision that immutable collections shouldn’t implement the standard mutable interfaces. The idea was that you had to explicitly call a method on them to convert them to the standard collection interfaces, such as ImmutableList
However, we received the feedback that people had a hard time figuring out how to pass an immutable list to en existing method that took, for example, IList
Also, we came to the conclusion that this design was inconsistent with our existing collection types. For example, List
In the end, we decided to remove the method to explicitly convert the collections to read-only collections and simply implemented the existing collection interfaces in a read-only fashion.
The following table summarizes the relationship between the immutable collections and the existing interfaces:
Equality semantics
Today, all collections in the BCL have reference equality semantics and don’t overload the equals operator (== in C#, = in Visual Basic).
In the preview release we chose to override the Object.Equals method to provide value equality, but did not overload the equals operator in line with the other collections. After reviewing this design more carefully we concluded that we don’t want to override the Equals method.
Value equality on collections can be fairly expensive to compute and comparing for equality on nested collections, such as ImmutableDictionary
In many cases, we believe that reference equality is sufficient. In other cases, the app should provide its own equality policy. As a result, we have removed the overrides of the Equals methods.
Naming
Several people pointed out that the design of our immutable collections is known as persistent data structures. Thus, it was suggested to rename our data types accordingly, for example, PersistentList
We want to keep the concept count low. The BCL already provides mutable collections, read-only collections, and now immutable collections. Traditionally, we don’t introduce new concepts unless deemed necessary.
From a high-level perspective, the important characteristic you get from immutable collections is that they guarantee that their contents will never ever change. The fact that these collections also enable you to efficiently create new versions of an existing instance without naively copying all their contents is of secondary importance. We feel the “Immutable” name focuses on the most important aspect.
In addition, we’ll consider adding an ImmutableArray
To me this indicates that “immutable” is a more useful term for the BCL as it is precise and yet general purpose enough to not require adding more terminology down the road when the design evolves.
The Small Things Count
We’ve also improved several smaller things, for example, we’ve added a ImmutableList
Hold on – aren’t those breaking changes?
Yes! The NuGet package is marked as a “pre-release”. Pre-release packages are non-stable previews of a product. That is, we don’t guarantee the final shape of the API and/or functionality and want to be able to change them based on customer feedback. In the end, the sole purpose of pre-release packages is gathering feedback.
That is a very different experience from a beta of the .NET Framework. Typically, a beta is the first public release of the framework but it is already very close to RTM. In fact, for .NET 4.5 we shipped the beta with a go-live license that supports use in production. On one hand, this is great for early adopters, but on the other hand it means we couldn’t react to major design change requests because the design was already set.
Pre-releases on NuGet allow us to give you the bits really early and react to your feedback in a meaningful way. For example, if changing the API shape is the right thing, we’ll do it.
However, once we mark packages as stable (AKA “RTM”) we hold the same bar for breaking changes as in-box .NET Framework components.
Summary
Please try out the new drop of immutable collections. If you’re already using them, you can simply upgrade your existing packages via the NuGet package manager. Otherwise, just search for Microsoft.Bcl.Immutable and make sure you include pre-releases.
Looking forward to receiving more feedback!