Mutable, Immutable and Generics

Immutable objects help with avoiding bugs. Suppose I have two interfaces implementing the Immutable Interface pattern. One interface for Point and one with MutablePoint. The pattern suggests a cast to ImmutablePoint p; ((Point)p).setX( 1.0 ); get the mutable interface. This isn’t safe and can be replaced with a Generics solution.

First we have the mutable point:

public interface MutablePoint {
   public void setX(int x);
   public void setY(int y);
}

which we want to create from an Immutable object without a cast:

  Point point = point(10,10);

  MutablePoint mPoint = point.makeMutable();
  mPoint.setX(20);

The second benefit beside the missing cast is that users of the Point interface know there is a mutable interface which they can get in a defined way.

The makeMutable() method comes from a generic interface called Mutable

public interface Mutable<T> {
   public T makeMutable();
}
 

which is extended by the Point interface.

public interface Point extends Mutable<MutablePoint> {
   public int getX();
   public int getY();
}

Our Point implementation now only needs to implement MutablePoint and Point. Voila.

public class DefaultPoint implements Point, MutablePoint {
   private int x = 0;
   private int y = 0;

   public DefaultPoint(int x, int y) {
      this.x = x;
	  this.y = y;
   }

   public int getX() { return this.x; }
   public void setX(int x) { this.x = x; }
   public int getY() { return this.y; }
   public void setY(int y) { this.y = y; }

   public Point point(int x, int y) {
		return new DefaultPoint(x,y);
   }

   public MutablePoint makeMutable() {
      return this;
   }

}

A negative side effect is that people who have a reference to a Point object can get a mutable version. When the main point is to have more immutable objects. The other way round is often better, have MutablePoint and create an immutable version.

Thanks for listening.

Update: As pointed out, making an mutable object from an immutable one will break the contract, as will making an immutable one from an mutable one. You do need to copy the object to be safe. For example with a BeanCopier or a copy constructor I’ve wrote about in Beautiful Java: Reflection and the BeanCopier. Better name the method asMutable than makeMutable

public MutablePoint asMutable() {
   return new DefaultPoint(this.x, this.y);
}

11 Responses to “Mutable, Immutable and Generics”  

  1. Gravatar Icon 1 Juanan

    great article!

    Just my 2 cents: I think that there’s a little bug. Instead of:

    Point point = point(10,10);

    it should be:

    Point point = new DefaultPoint(10,10);

    isn’t it?

  2. Gravatar Icon 2 stephan

    Thanks :-)

    point() is a factory (Fluent Interface style), see the method in DefaultPoint:


    public Point point(int x, int y) {
    return new DefaultPoint(x,y);
    }

    For more code this could be packaged into a new Object PointFactory oder PointBuilder.

  3. Gravatar Icon 3 Arnold

    Probably it’s just a matter of taste. But the mutable state of a bean could
    also be considered to be a cross cutting concern.
    Another approach could therefore be to implement this concern separately
    instead of as part of the bean itself.
    Personally I would therefore favor the creation of a dynamically proxied Pointer
    that wraps the original Pointer and throws an IllegalStateException when the settter
    is called. One could implement this approach by using java.lang.reflect.Proxy
    But again, maybe it’s just a matter of taste.

  4. Gravatar Icon 4 stephan

    Yes, at least I can follow the argumentation.

    With Qi4j I also would model the mutable state as a different concern.

    http://www.jroller.com/rickard/entry/qi4j_status_report

  5. Gravatar Icon 5 Maz

    Hi Stephan,

    The big advantage of immutable Objects is that they are immutable and their state will not change. Otherwise you have to take care about synchronization and the java memory model.
    So your suggestion will break the immutable contract.

    I would have expected to get a new mutable object by changing to mutable. By the I would also expect to be able to have the possibility to get a immutable version from the mutable object.

    So the makeMutable method needs a modification:
    # public MutablePoint makeMutable() {
    # return new DefaultPoint(x,y);
    # }

    Anyway, the DefaultPoint ist not really an immutable object, so it is not the best practice to use this kind of code and rely on the immutablity of the point.

  6. Gravatar Icon 6 stephan

    @Maz: Of course, you are right. Good point.

  7. Gravatar Icon 7 lumpynose

    Regarding Arnold’s remark about using a proxy, what about the “old fashioned” way of using inheritance? For example, see below. What I like about this way is that you can have a method that returns either a ReadOnlyPoint or a ReadWritePoint, but declares that it returns a ReadOnlyPoint;

    public APIReadOnlyPoint getPoint();

    The users of that method know that they’re getting a point that they cannot call the setters on, and the compiler won’t let them. No chance of exceptions being thrown.

    public interface APIReadOnlyPoint {
    public T getX();

    public T getY();
    }

    public interface APIReadWritePoint extends APIReadOnlyPoint {
    public void setX(T x);

    public void setY(T y);
    }

    public class ReadOnlyPoint implements APIReadOnlyPoint {
    protected T x;
    protected T y;

    public ReadOnlyPoint(final T x, final T y) {
    this.x = x;
    this.y = y;
    }

    @Override
    public T getX() {
    return x;
    }

    @Override
    public T getY() {
    return y;
    }
    }

    public final class ReadWritePoint extends ReadOnlyPoint implements
    APIReadWritePoint {
    public ReadWritePoint(final T x, final T y) {
    super(x, y);
    }

    public ReadWritePoint(final ReadOnlyPoint point) {
    super(point.getX(), point.getY());
    }

    @Override
    public void setX(final T x) {
    this.x = x;
    }

    @Override
    public void setY(final T y) {
    this.y = y;
    }
    }

  8. Gravatar Icon 8 stephan

    @lumpynose: How do you get a ReadOnlyPoint from an ReadWritePoint and vice versa without a cast?

  9. Gravatar Icon 9 Maz

    @lumpynose
    By definition protected members are not immutable even if the class itself does not support any setters. There could be subclasses modifying the members and your code could not rely an the immutibility.

    So this raise the question of the meaning of immutable objects.
    Immutable objects are under no condition modifiable. Best examples are the object representations of primitives (Integer, Boolean, etc.) and String.
    JDK 1.3 could gain a huge performance gain by caching all strings and string creation and comparision was almost done in no time.

    It is really nice to see what is possible with generics as Stephan demonstrated, but for this case it would rather be advisable to keep things simple and just have two different classes: One mutable and one immutable if really needed.

    public interface Point
    {
    int getX(); int getY();
    }

    public class ImmutablePoint implements Point
    {
    private int x;
    private int y;
    public int getX(){return x;}
    public int getY(){return y;}

    public ImmutablePoint(int x1, int y1)
    {
    x=x1;y=y1;
    }

    public MutablePoint mutablePoint()
    {
    return new MutablePoint(x,x);
    }
    }

    public class MutablePoint implements Point
    {
    protected int x;
    protected int y;

    public int getX(){return x;}
    public int getY(){return y;}

    public void setX(int x1){x=x1;}
    public void setY(int y1){y=y1;}

    public MutablePoint(int x1, int y1)
    {
    x=x1;y=y1;
    }

    public ImmutablePoint immutablePoint()
    {
    // we could here also lookup in a cache for a immutable object representing the Point and return only this instance.
    return new ImmutablePoint(x,y);
    }
    }

  10. Gravatar Icon 10 lumpynose

    @stephan
    I’m thinking of simple value objects, so the conversions would be done via constructors that copy the object. That’s why I have the constructor ReadWritePoint(final ReadOnlyPoint point). For going the other way, from ReadWritePoint to ReadOnlyPoint, you could have a method in ReadOnlyPoint that takes as its argument a ReadWritePoint and declares that it returns a ReadOnlyPoint;

    public APIReadOnlyPoint asReadOnly(APIReadWritePoint point) {
    return(point);
    }

  11. Gravatar Icon 11 lumpynose

    I’m thinking that my asReadOnly doesn’t need an argument and can simply return ‘this’ and move the method to the ReadWritePoint class.

Leave a Reply



RSS