What are the drawbacks of immutable types?

I see myself using more and more immutable types when the instances of the class are not expected to be changed. It requires more work (see example below), but makes it easier to use the types in a multithreaded environment.

At the same time, I rarely see immutable types in other applications, even when mutability wouldn’t benefit anyone.

Question: Why immutable types are so rarely used in other applications?

  • Is this because it’s longer to write code for an immutable type,
  • Or am I missing something and there are some important drawbacks when using immutable types?

Example from real life

Let’s say you get Weather from a RESTful API like that:

public Weather FindWeather(string city)
{
    // TODO: Load the JSON response from the RESTful API and translate it into an instance
    // of the Weather class.
}

What we would generally see is (new lines and comments removed to shorten the code):

public sealed class Weather
{
    public City CorrespondingCity { get; set; }
    public SkyState Sky { get; set; } // Example: SkyState.Clouds, SkyState.HeavySnow, etc.
    public int PrecipitationRisk { get; set; }
    public int Temperature { get; set; }
}

On the other hand, I would write it this way, given that getting a Weather from the API, then modifying it would be weird: changing Temperature or Sky wouldn’t change the weather in real world, and changing CorrespondingCity doesn’t make sense neither.

public sealed class Weather
{
    private readonly City correspondingCity;
    private readonly SkyState sky;
    private readonly int precipitationRisk;
    private readonly int temperature;

    public Weather(City correspondingCity, SkyState sky, int precipitationRisk,
        int temperature)
    {
        this.correspondingCity = correspondingCity;
        this.sky = sky;
        this.precipitationRisk = precipitationRisk;
        this.temperature = temperature;
    }

    public City CorrespondingCity { get { return this.correspondingCity; } }
    public SkyState Sky { get { return this.sky; } }
    public int PrecipitationRisk { get { return this.precipitationRisk; } }
    public int Temperature { get { return this.temperature; } }
}

9

I program in C# and Objective-C. I really like immutable typing, but in real life I’ve been always forced to limit its usage, mainly for data types, for the following reasons:

  1. Implementation effort comparing to mutable types. With an immutable type, you would need to have a constructor requiring arguments for all properties. Your example is a good one. Try imagining that you have 10 classes, each having 5-10 properties. To make things easier, you might need to have a builder class to construct or create modified immutable instances in a manner similar to StringBuilder or UriBuilder in C#, or WeatherBuilder in your case. This is the main reason for me as many classes I design are not worth such an effort.
  2. Consumer usability. An immutable type is more difficult to use in comparison to mutable type. Instantiation requires initialising all values. Immutability also means that we cannot pass the instance to a method to modify its value without using a builder, and if we need to have a builder then the drawback is in my (1).
  3. Compatibility with the language’s framework. Many of the data frameworks require mutable types and default constructors to operate. For example, you cannot do nested LINQ-to-SQL query with immutable types, and you cannot bind properties to be edited in editors such as Windows Forms’ TextBox.

In short, immutability is good for objects that behave like values, or only have a few properties. Before making anything immutable, you must consider the effort needed and the usability of the class itself after making it immutable.

6

Just generally immutable types created in languages that don’t revolve around immutability will tend to cost more developer time to create as well as potentially use if they require some “builder” type of object to express desired changes (this does not mean that the overall work will be more, but there is a cost upfront in these cases). Also regardless of whether the language makes it really easy to create immutable types or not, it’ll tend to always require some processing and memory overhead for non-trivial data types.

Making Functions Devoid of Side Effects

If you are working in languages that don’t revolve around immutability, then I think the pragmatic approach is not to seek to make every single data type immutable. A potentially far more productive mindset which gives you many of the same benefits is to focus on maximizing the number of functions in your system that cause zero side effects.

As a simple example, if you have a function which causes a side effect like this:

// Make 'x' the absolute value of itself.
void make_abs(int& x);

Then we don’t need an immutable integer data type that forbids operators like post-initialization assignment to make that function avoid side effects. We can simply do this:

// Returns the absolute value of 'x'.
int abs(int x);

Now the function doesn’t mess with x or anything outside of its scope, and in this trivial case we might have even shaved some cycles by avoiding any overhead associated with the indirection/aliasing. At the very least the second version shouldn’t be more computationally expensive than the first.

Things That Are Expensive to Copy in Full

Of course most cases aren’t this trivial if we want to avoid making a function cause side effects. A complex real-world use case might be more like this:

// Transforms the vertices of the specified mesh by
// the specified transformation matrix.
void transform(Mesh& mesh, Matrix4f matrix);

At which point the mesh might require a couple hundred megabytes of memory with over a hundred thousand polygons, even more vertices and edges, multiple texture maps, morph targets, etc. It’d be really expensive to copy that whole mesh just to make this transform function free of side effects, like so:

// Returns a new version of the mesh whose vertices been 
// transformed by the specified transformation matrix.
Mesh transform(Mesh mesh, Matrix4f matrix);

And it’s in these cases where copying something in its entirety would normally be an epic overhead where I’ve found it useful to turn Mesh into a persistent data structure and an immutable type with the analogical “builder” to create modified versions of it so that it can simply shallow copy and reference count parts which aren’t unique. It’s all with the focus of being able to write mesh functions which are free of side effects.

Persistent Data Structures

And in these cases where copying everything is so incredibly expensive, I found the effort of designing an immutable Mesh to really pay off even though it had a slightly steep cost upfront, because it didn’t just simplify thread safety. It also simplified non-destructive editing (allowing the user to layer mesh operations without modifying his original copy), undo systems (now the undo system can just store an immutable copy of the mesh prior to the changes made by an operation without blowing up memory use), and exception-safety (now if an exception occurs in the above function, the function doesn’t have to roll back and undo all of its side effects since it didn’t cause any to begin with).

I can confidently say in these cases that the time required to make these hefty data structures immutable saved more time than it cost, since I’ve compared the maintenance costs of these new designs against former ones which revolved around mutability and functions causing side effects, and the former mutable designs cost far more time and were far more prone to human error, especially in areas that are really tempting for developers to neglect during crunch time, like exception-safety.

So I do think immutable data types really pay off in these cases, but not everything has to be made immutable in order to make the majority of the functions in your system free of side effects. Many things are cheap enough to just copy in full. Also many real-world applications will need to cause some side effects here and there (at the very least like saving a file), but typically there are far more functions which could be devoid of side effects.

The point of having some immutable data types to me is to make sure we can write the maximum number of functions to be free of side effects without incurring epic overhead in the form of deep copying massive data structures left and right in full when only small portions of them need to be modified. Having persistent data structures around in those cases then ends up becoming an optimization detail to allow us to write our functions to be free of side effects without paying an epic cost to doing so.

Immutable Overhead

Now conceptually the mutable versions will always have an edge in efficiency. There is always that computational overhead associated with immutable data structures. But I found it a worthy exchange in the cases I described above, and you can focus on making the overhead sufficiently minimal in nature. I prefer that type of approach where correctness becomes easy and optimization becomes harder rather than optimization being easier but correctness becoming harder. It’s not nearly as demoralizing to have code that functions perfectly correctly in need of some more tune ups over code that doesn’t function correctly in the first place no matter how quickly it achieves its incorrect results.

The only drawback I can think of is that in theory use of immutable data may be slower than mutable ones – it is slower to create a new instance, and collect previous one than to modify existing one.

The other “problem” is that you can’t only use immutable types. In the end you have to describe the state and you have to use mutable types to do so – without changing state you can’t do any work.

But still general rule is to use immutable types wherever you can and make types mutable only when there really is a reason to do so…

And to answer the question “Why immutable types are so rarely used in other applications?” – I really don’t think they are… wherever you look everyone recommends making your classes as immutable as they can be… for example: http://www.javapractices.com/topic/TopicAction.do?Id=29

8

To model any real-world system which where things can change, mutable state will need to be encoded somewhere, somehow. There are three main ways an object can hold mutable state:

  • Using a mutable reference to an immutable object
  • Using an immutable reference to a mutable object
  • Using a mutable reference to a mutable object

Using first makes it easy for an object to make an immutable snapshot of the present state. Using the second makes it easy for an object to create a live view of the present state. Using the third can sometimes make certain actions more efficient in cases where there’s little expected need for immutable snapshots nor live views.

Beyond the fact that updating state stored using a mutable reference to an immutable object is often slower than updating state stored using a mutable object, using a mutable reference will require one to forgo the possibility of constructing a cheap live view of the state. If one won’t need to create a live view, that’s not a problem; if, however, one would need to create a live view, an inability to use an immutable reference will make all operations with the view–both reads and writes–much slower than they otherwise would be. If the need for immutable snapshots exceeds the need for live views, the improved performance of immutable snapshots may justify the performance hit for live views, but if one needs live views and doesn’t need snapshots, using immutable references to mutable objects is the way to go.

In your case the answer is mainly because C# has poor support for Immutability …

It would be great if:

  • everything will be immutable by default unless noted otherwise (ie with a ‘mutable’ keyword), mixing immutable and mutable types is confusing

  • mutating methods (With) will be automatically available – though this can already be achieved see With

  • there will be a way to saying the result of a specific method call (ie ImmutableList<T>.Add) cannot be discarded or at least will produce a warning

  • And mainly if the compiler could as much as possible ensure immutability where requested (see https://github.com/dotnet/roslyn/issues/159)

1

Why immutable types are so rarely used in other applications?

Ignorance? Inexperience?

Immutable objects are widely regarded as superior today, but it’s a relatively recent development. Engineers who haven’t kept up to date, or are simply stuck in ‘what they know’ won’t use them. And it does take a bit of design changes to use them effectively. If the apps are old, or the engineers weak in design skills then using them might be awkward or otherwise troublesome.

7

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật