Sponsored Link •
Bill Venners: You just said "value types." The last time I talked to James Gosling, I asked him when would he make a class immutable versus mutable. He said he'd make classes immutable whenever he could, because you don't have to worry about cloning it before you pass it and so on. In your book you seem reiterate that philosophy. The way I have always thought about immutables, though, was primarily as value classes. The kind of classes that felt like immutables to me were things like a complex number, a big integer, a bit set, or maybe a matrix. But if I have an abstraction that models, say, a vending machine, where I have money going in and candy bars coming out, that looks like a state machine and feels to me like a mutable object. When would you use immutables in designs?
Josh Bloch: There are all sorts of ways you could design a vending machine. For starters, you'll probably have a type to represent the state. By all means, that should be immutable.
The type to represent the state could be either type-safe enum or a primitive
int. You should probably use a type-safe enum. If I have a variable deep in the bowels of my machine that represents the current state, the last thing I want is somebody else from the outside being able to change the state of my machine by modifying this object that's doing nothing but holding the state.
So, I think there is a place for immutability, even if you decide to go with the mutable design, which I think is perfectly reasonable. There is a way to do a state machine immutably, which is basically to duplicate the entire machine each time you do a state transition. But I think that is forced, and I don't do that sort of design generally.
You can look at things that I've done, where there is a state transition diagram, like the
Timer class in
Timer object does go through state transitions. But that said, I think that when you are designing a state transition system, you should make it as simple as possible -- in a sense, as immutable as possible.
So if something is naturally modeled as a state machine, then clearly, there would be a mutable object that is the state machine. But on the other hand, you should carefully analyze the state transition diagram, make it as simple as possible--give it as few states as possible and as few arcs as possible. And then you should document the thing to a T. Most of the really broken classes that I have dealt with are the ones that have complicated state transition diagrams that were not well documented. If a state transition diagram isn't well documented, people just can't use the class. Client code that works will break in the next release because the implementation will be changed in a way that subtlety changes the state transition diagram. Because it was never documented in the first place, people depend on implementation details that are no longer accurate. So whenever you have mutable classes, you should be very conscious of the fact that there is a state transition diagram, and you should document it to your user.
This is one of the big differences between APIs designed by people with a lot of experience APIs designed by novices. Experienced programmers really do try to minimize the state space and the people with less experience don't realize that this is an important aspect of any API.
Bill Venners: Sounds like the guideline is "minimize mutability."
Josh Bloch: Absolutely. It's funny you should phrase it that way, because I once gave a talk on API design where each section had an alliterative title. And I came up with the same alliteration that you did.