views:

260

answers:

4

I want to have immutable Java objects like this (strongly simplyfied):

class Immutable {

    protected String name;

    public Immutable(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

}

In some cases the object should not only be readable but mutable, so I could add mutability through inheritance:

public class Mutable extends Immutable {

    public Mutable(String name) {
        super(name);
    }

    public void setName(String name) {
        super.name = name;
    }

}

While this is technically fine, I wonder if it conforms with OOP and inheritance that mutable is also of type immutable. I want to avoid the OOP crime to throw UnsupportedOperationException for immutable object, like the Java collections API does.

What do you think? Any other ideas?

+4  A: 

Immutable classes should be final precisely to avoid mutable sub-types.

Allowing a sub-type of an immutable class to break the immutable contract makes it rather pointless to have the class be immutable in the first place. It may be legal in the sense that Java allows you to do it (immutability is not enforced in the language) but such a class isn't truly immutable as long as it can be sub-classed.

This is why String is final.

Kris
Consider you need ImmutableCollection base class and ImmutableList, ImmutableSet subclasses. How can you make here base class final?The thing is that no compiler can express all contraints that may appear in your model. Thus we should expect that compiler will check everything for us.
Alexey
+9  A: 

Avoid calling the parent "Immutable" because it becomes a lie in the child class - if you do want to make a class immutable, it should be final too in order to prevent exactly this problem.

Joda Time uses "ReadableXXX" to give the idea that "this class only provides read access; other subclasses may be mutable". I'm not sure whether I like that idea, but I can't say I've seen many alternatives.

Basically the problem is with expressing a negative - Immutable describes what you can't do (mutate it) and that can't be sensibly enforced in subclasses. (Even if the fields within Immutable were final, it wouldn't stop a subclass having its own mutable fields.)

Jon Skeet
+1  A: 

I find your code rather curious.

To implement such an Immutable behaviour, I would rather has relied upon an Immutable interface, providing only the getter method, whiile the object contains both. This way, operations relying on the immutable objects would have called the interface, while others would have called the object.

And, if you really don't want your immutable objects to be casted as mutable ones, you can then use proxies, and all the enterprise tools (aspects, and so on). But usually, relying upon other developpers' goodwill is a sweet way to make them responsible of their mistakes (like casting the immutable in mutable).

Riduidel
+5  A: 

Your subclass is bad because it violates the Liskov substitution principle. Don't do it.

LES2