[concurrency-interest] Joda-Time immutability

Gregg Wonderly gregg at cytetech.com
Tue Jun 21 09:13:29 EDT 2011


On 6/21/2011 3:11 AM, Mark Thornton wrote:
> On 21/06/11 07:27, Mark Thornton wrote:
>> On 20/06/11 11:33, Stephen Colebourne wrote:
>>> In Joda-Time way back when we structured the code in a complex manner
>>> and then claimed immutability. This is causing difficulty to try and
>>> obey proper immutability standards, and I'd like any ideas on fixes.
>>>
>>> Consider the "immutable" class DateTime. The hierarchy is as follows:
>>>
>>> AbstractInstant
>>> AbstractDateTime
>>> BaseDateTime
>>> DateTime / MutableDateTime
>>>
>>> https://github.com/JodaOrg/joda-time/tree/master/src/main/java/org/joda/time
>>> https://github.com/JodaOrg/joda-time/tree/master/src/main/java/org/joda/time/base
>>>
>>>
>>> The two Abstract prefixed classes are not an issue, as they just share
>>> code and contain no state. However the BaseDateTime contains all the
>>> state (and DateTime/MutableDateTime contain no state).
>>>
>>> As a result of this (bad) design, the instance variables in
>>> BaseDateTime are not final (as they need to be mutated by the
>>> MutableDateTime subclass). The DateTime ("immutable") subclass is thus
>>> storing its state in regular mutable variables in BaseDateTime. Under
>>> the memory model, claiming DateTime as immutable is wrong.
>> A possible solution:
>>
>> Make the fields in BaseDateTime final.
>> DateTime is left unchanged.
>> Duplicate the fields in MutableDateTime with getter/setters referring to the
>> new (mutable) fields.
>>
>> Add a readObject method to MutableDateTime which calls
>> ObjectInputStream.readFields. If the new fields are present (test using
>> GetFields.defaulted) then we are restoring from a serialization of the new
>> form of the class; just restore them as usual. If the fields are missing, then
>> the serialized form was from the old class, in this case copy the values from
>> the immutable values in BaseDateTime.
>>
>> Note I have not tried this.
>>
>> Mark Thornton
>>
> An even simpler method would modify MutableDateTime as follows
>
> public class MutableDateTime extends BaseDateTime {
> private long iMillis;
> private Chronology chronology;
>
> private void readObject(ObjectInputStream in) throws ... {
> iMillis = super.getMillis();
> chronology = super.getChronology();
> in.defaultReadObject();
> }

When there is an object reference involved in this kind of change, we've always 
just done

private void readObject( ObjectInputStream in ) throws ... {

	in.defaultReadObject();

	// If this is the first time to deserialize with the new
	// mutable fields in place, copy the values from the old
	// final fields.
	if( chronology == null ) {
		iMillis = super.getMillis();
		chronology = super.getChronology();
	}
}

This is a little easier to understand so that people don't wonder why you are 
doing things out of order.  A comment on the other version would perhaps detail
what is important about the ordering of statements there too.

Gregg Wonderly


More information about the Concurrency-interest mailing list