Mutable, Immutable and Generics
Published April 28th, 2008 in JavaImmutable 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);
}
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?
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
PointFactoryoderPointBuilder.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.
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
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.
@Maz: Of course, you are right. Good point.
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;
}
}
@lumpynose: How do you get a ReadOnlyPoint from an ReadWritePoint and vice versa without a cast?
@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);
}
}
@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);
}
I’m thinking that my asReadOnly doesn’t need an argument and can simply return ‘this’ and move the method to the ReadWritePoint class.