The Artima Developer Community
Sponsored Link

Josh Bloch on Design
A Conversation with Effective Java Author, Josh Bloch
by Bill Venners
First Published in JavaWorld, January 4, 2002

<<  Page 10 of 19  >>

Advertisement

Documenting Immutability

Bill Venners: Should I document in the contract of a class that it is immutable? If I don't, I may have the option of making the class mutable in a future version. But if I don't mention immutability in the contract of the class, clients may feel the need to clone instances of it before passing them to or from methods. If I do document immutability and the class is subclassable, then I'm basically relying on the kindness of the person who does the subclass to make sure the subclass is also immutable.

Josh Bloch: If it's not subclassable, then you are documenting it, assuming you are documenting your class properly, whether you use the words "represents an immutable complex number" or not. If the set of operations that you have does not permit mutation, then you have documented that it's immutable.

I think you should document as clearly as possible, though, so I think using the word immutable is not a bad idea at all. If it's subclassable, then it's actually part of the contract that the subclasser must maintain, so I think you should get right out and say, "These are immutables," so anyone making subclasses knows they should maintain that immutability.

But as you've alluded to, subclassability and immutability are somewhat at odds with one another. It is possible to do something that's both immutable and extendable but it demands great care. The most you can do, if you assume an unfriendly subclasser, is to make all the methods final and say, "You are permitted to add methods to this." Because the moment you start letting someone override the methods, they can do things that imply mutability.

For example, let's say you're subclassing String (in some alternate universe where it isn't final). Any of the operations that actually do something to the String, that search for substrings, etc., can return different results depending on when they are called. They can return random results, if you really have a sense of humor. And in doing so, you would have broken the immutability of String.

So if you want something both subclassable and immutable, you better make all the methods final. This raises the question, why bother making it subclassable? Why not just make it final or make no accessible constructors? Let someone who wants to add methods write a "utility class" consisting of static methods that take one of the things on input.

Generally speaking, my view is that classes that are immutable should not be subclassable, and I've goofed in this area. The first big thing that I did when I arrived here in 1996 was java.math. If you look at BigInteger and BigDecimal, you'll see that they are both immutable and subclassable. I know in my heart of hearts that this is wrong. In fact, the methods aren't final, so you can make a BigInteger appear mutable by subclassing it and then just lying in response to add and multiply and divide operations. Whereas you can't do this with String because it's genuinely immutable: String is final, so it does what it says it does.

Bill Venners: That makes sense, but I think it also conflicts somewhat with what you said earlier (in Part I of this interview) about trusting that classes implement their contract. A subclass is a class. If its contract says that it must maintain immutability, then should we trust it to do that? It's a hard line to draw. When do I trust and when do I stop trusting?

Josh Bloch: You need to trust, but on the other hand, you can also obey reasonable caution. It is true that when you allow subclassing, you are opening the door for more difficulties, so you should only do this if you have a good reason to do it. This is something that I arrived at over time. Subclassing is great for certain things. In particular, I think within a library--within a trust boundary--it's just great. If you are implementing a whole bunch of different collections classes, it's really nice if you can share a mechanism by subclassing.

For example, LinkedHashMap extends HashMap. All the hashing stuff is inside HashMap. It works nicely. But on the other hand, once you do this across libraries you are trusting people who maybe you shouldn't trust, because it's the world at large that you are trusting. And you have to ask yourself, "What am I getting in exchange for this?"

When it comes down to these immutable value types, what you're getting in exchange for it is you are letting people add methods to your immutable value type. It's not clear that this is important. When I am using somebody else's class, I'm just as happy to write a static utility class to "add" methods. And I would hope that other people are happy to do the same thing to my classes.

So, basically, I think you shouldn't make something extendable unless you have a good reason to do it.

<<  Page 10 of 19  >>


Sponsored Links



Google
  Web Artima.com   
Copyright © 1996-2009 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use - Advertise with Us