[concurrency-interest] Joda-Time immutability

Mark Thornton mthornton at optrak.com
Tue Jun 21 09:23:50 EDT 2011


On 21/06/11 14:13, Gregg Wonderly wrote:
> 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

That only works where the Object reference is non nullable. You could 
use the same technique with any field where the default value is 
invalid. You are quite right that the code should be documented, and 
especially the significance of the statement ordering. With just two 
fields I doubt there is much performance difference.

Mark






More information about the Concurrency-interest mailing list