[concurrency-interest] Immutable object conundrums

Ashley Williams ashpublic at mac.com
Tue Jun 30 07:54:37 EDT 2009


Hi,

Like most developers I have worked with, the only immutable objects I  
create are more to do with keeping
control over internal data. For example I might return an unmodifiable  
list from a method so that I know it
can't have its content modified.

Changing styles in order to use many more immutable objects for the  
purposes of thread safety represents
a great challenge, at least for me, so I thought I'd jot down some  
thoughts in the hope that anyone who
has gone through a similar experience might comment on any part of  
this post.

----------------------------------------------

1. final doesn't imply immutable intentions.

It seems to me that immutability for the sake of propagating  
constructor changes to main memory
is something of a misnomer - this is more about using the 'final'  
keyword as a coarse grained hook into the
java memory model. Maybe if we had more direct access to that memory  
model then we could ensure
that mutable objects could safely be constructed as well, for example:

public class MyMutableClass {
    private String myNonFinal;

    public MyClass() {
       this.myNonFinal = "hello world";
       MemoryModel.flush(); // flush-commit similar to other cache  
technologies
    }
}

So my suggestion is that sometimes we rely on the side effects of  
'final' to help with safe publication rather
than expressing a desire to express immutable semantics. The only way  
I can see to gain the best of both
worlds is to use java atomics, which I can declare final but whose  
contents I can modify.

----------------------------------------------

2. Immutable Objects in aggregations and compositions

Unless an object is nothing more than a glorified utility then the  
chances are that it is a child component in some
parent aggregate. If this child component is mutable then one of the  
tactics I can use is to change the methods
that otherwise modify state, to return modified copies of itself  
instead:

public class MyParent {
    private MyChlld myChild;
    public void setChild(MyChild child) {...}
    public MyChild getChild() {...}
}

public class MyChild {
    public MyChild modify() {} // returns modified copy just like  
String.replace() does for example
}


Then I have to update the parent aggregate with the return value from  
MyChild.modify(). But if ThreadA and ThreadB
both try to do this then I have to consider the possibility that one  
of the updates will be overwritten by the other. So
rather than immutable objects being a silver bullet, I now appear to  
be firmly in the territory of lost-updates,
unrepeatable reads and other isolation problems. Is this an  
inevitability, or is there some other way people out there
are designing their way round this?

Maybe true concurrency should be limited just to a few well understood  
homogeneous bottleneck tasks and the rest
of the system should be synchronized with a strict locking policy,  
which would mean that many mutable objects
could remain in a kind of non-concurrent sandbox.

----------------------------------------------

3. immutable objects may require mutable construction

Yes there are many occasions when immutable objects are called for,  
but unless they are very trivial they
require great care in their construction. One technique I often use is  
to provide only the most basic constructors
and provide post construction methods to allow for further  
configuration. The documented understanding is that
you call the constructor followed by the post-construction methods in  
order to set the object up. The rest of
the API is immutable, just don't call the post-construction methods  
again.

// logically mutable even though it contains mutator methods
public class MyLogicallyImmutableClass {
    public MyLogicallyImmutableClass() {}

    @PostConstruction
    public MyLogicallyImmutableClass setParent(Object parent) {}

    @PostConstruction
    public MyLogicallyImmutableClass setData(int x, int y, int z) {...}
}

As an example I wouldn't normally set up the parent/child relationship  
in the constructors so the setParent() method
must separately be called, but 'parent' would be an immutable property  
from then on. So how would I handle
this situation - would I pepper my code with lots of factories and  
builders and move the post-construction data into
proper constructors? If so then I don't see how I can properly set up  
parent and child relationships in the light of
Domain Driven Design (Eric Evans) concerns where relationships are set  
up outside of the constructors.



Many thanks if you read this far!
- Ashley Williams



More information about the Concurrency-interest mailing list