The Problem with Immutability

I’m writing this partly because I think there must be a happy solution and I just can’t find it.

I love immutability. Not all the time, but many times. I’d like to identify values which either because problems when they are changed, or they just do nothing. Of course reference variables generally need to be immutability, but they can also generally be initialized without any data – for example you can set a collection variable to an empty list in the declaration or the constructor.

The problem occurs with data happy classes – classes with strings or dates or integers or strings – where it is either dangerous or useless to set the values.

In traditional coding where you explicitly call a constructor, all is happy because you can create read only variables. You can assign to these variables in the constructor and they can’t be assigned to again.

But enter composition, MEF, IoC, whatever. Now, how do you manage those immutable values?

I’ve come up with four solutions:

a) Provide an Initialize method with positional parameters

b) Provide an Initialize method with optional named parameters

c) Write ugly code that tracks values and issues runtime errors

d) Provide a second interface that allows the sets

e) Use a singleton factory strongly bound to the actual class

f) Forget immutability

I’ll veto c for my work. Not only is it extra stupid code everywhere, but it throws runtime, not compile time errors.

If you need things to be “kind of, sort of” immutable, the interface trick would work. In some cases you might be able to limit visibility of the interface. But it’s not immutable.

I hate initialize methods. You have to remember to call them and its extra thinking. Without optional/named parameters they are extremely fragile to parameter list changes. And, it would be so weird to call Initialize twice on an object that I’m OK with the runtime error for that, and it can refuse to reset the values so you have nearly true immutability.

It’s not true immutability because the variables must be writable from within the class – for example, you could use private setters. This means within the class, the values can be changed rendering them less than fully immutable.

You could solve this problem if you created custom factories for every class you would instantiate items of. Instead of retrieving the new value via composition/MEF, retrieve the singleton factory. The factory could be hard wired to the actual class and thus directly call the constructor. A method like “Instantiate” could take as many parameters as needed, and could use optional and named parameters to avoid parameter list fragility issues.

This leaves me less than enamored with PartInitializer. It encourages us to skip immutability or to take shortcuts that leave our classes less than fully immutable. I’m not enamored with custom factories either. They are only a few lines of code, but they barf an implementation detail all over our code. Significant ceremony.

I’d beat up on the MEF team if I could figure out a way they could solve this with minimal ceremony.

Anyone have a great solution?

8 thoughts on “The Problem with Immutability”

  1. I think the answer you’re looking for is to also make the immutable values you wish to pass composable.

    The object you’re creating via MEF should retrieve it’s values by also using MEF (or importing). So the object that current has the immutable values would expose them as read-only properties and the object being imported would also import the object it’s being exported to. Call the properties, done. You’ve achieved loose coupling.

  2. Justin,

    Composing values from the container makes sense when there are a handful of values with a long lifetime – like singletons.

    I do use nested containers and container provided values, but for different reasons that transient instantiation.

    When you have a dozen values from a single source going to a single composed instance in a transient way… well, that means you’re putting a dozen values in the container where they will stay and you expect the next person picking them up will be the constructor you intend to use. And since the values is changing up until the moment you call the constructor, you need to be sure the value is in the container – which you could do by delegates.

    You can solve the “in the container where it will stay” by creating a nested container. This avoids risking leaks or crossing data over between instantiations (assuming the nested container is confined to the thread. But this potentially means creating a nested composition container every time I create a new instance. That barfs implementation details across the system.

    You are correct that it should be another option on my list but I think it generally makes sense for singletons with singleton data values.

    Do you think it’s simpler than I am describing? Have you actually made it work?


  3. Would I be correct in understanding the problem as one of parameterisation?

    E.g. in Autofac and many IoC containers, one can merge ‘transient’ parameter values with container-provided services in a constructor:

    class Foo : IFoo
    public Foo(string n, IBar bar) { }

    var foo = container.Resolve(new NamedParameter(“n”, “Fred”));

    Here n is passed by the requestor while bar comes from the container.

    Both n and bar can therefore be assigned to readonly fields.

    Parameterisation would be a really nice addition to MEF.

  4. Nick,

    Hi! How is life in Oz?

    Yes, it’s a parameterization problem. It isn’t always logical to stick things into the container for an importing constructor.

    I am afraid I am so MEF focused I didn’t realize that Autofac had this. Sounds like something to push for in VNext MEF!


  5. Kathleen,

    This is a non-issue with modern containers. As Nick pointed out, it can be trivially achieved with AutoFac, Castle Windsor has also multiple ways of providing just-in-time values to the components: TypedFactoryFacility, DynamicParameters or OnCreate method to name a few.

  6. I have to admit I’m not 100% sure I’m on the same page as you but I have been using MEF a lot lately and my solution was to basically create two interfaces IContext and IContextContainer.

    IContext is basically a ServiceProvider where MEF composition is just one type of service (ICompositionContainerService). Then whenever you register a service if it implements IContextContainer you call Initialize(this) to give it the context.

    As it’s initializing you can then pull in any service you might need to get your variables. In this case this is all for use in a Pipeline. The pipeline will accept multiple contexts each will have a set of services it needs to accomplish its task, some are shared (if safe) some are unique for each context. Each context is run through the pipeline in parallel.

    Here is an example of a pipeline step consuming the context (ServiceProvider should be renamed to Context):

    That’s how I achieve extreme modularity as well as immutability which makes the steps re-usable and safe to run in parallel. There are very few property setters anywhere. When you create the pipeline you give it all the input it needs, some steps will register services (like parameters in your words) for following steps.

    I hope this helps some.

Leave a Reply

Your email address will not be published. Required fields are marked *