tags:

views:

774

answers:

11

When a getter returns a property, such as returning a List of other related objects, should that list and it's objects be immutable to prevent code outside of the class, changing the state of those objects, without the main parent object knowing?

For example if a Contact object, has a getDetails getter, which returns a List of ContactDetails objects, then any code calling that getter:

  1. can remove ContactDetail objects from that list without the Contact object knowing of it.
  2. can change each ContactDetail object without the Contact object knowing of it.

So what should we do here? Should we just thrust the calling code and return easily mutable objects, or go the hard way and make a immutable class for each mutable class?

+4  A: 

If you have control of the calling code then what matters most is that the choice you make is documented well in all the right places.

Liam
+1  A: 

I used to return a read-only version of the list, or at least, a copy. But each object contained in the list must be editable, unless they are immutable by design.

Romain Verdier
+2  A: 

Depends on the context, really. But generally, yes, one should write as defensive code as possible (returning array copies, returning readonly wrappers around collections etc.). In any case, it should be clearly documented.

petr k.
+6  A: 

It's a matter of whether you should be "defensive" in your code. If you're the (sole) user of your class and you trust yourself then by all means no need for immutability. However, if this code needs to work no matter what, or you don't trust your user, then make everything that is externalized immutable.

That said, most properties I create are mutable. An occasional user botches this up, but then again it's his/her fault, since it is clearly documented that mutation should not occur via mutable objects received via getters.

Shachar
That's an interesting differentiation to make--weather or not you own the code. I NEVER think of anything outside the class I'm writing as safe. I'm not convinced there is an advantage to coding with the assumption that anyone calling you will always get it right... Can it actually be faster to skip a few lines of typing if once in your career it costs someone 20 or 30 minutes of debugging? Typing those extra lines are virtually free compared to the time you spend on a project..
Bill K
+1  A: 

I think you'll find that it's very rare for every gettable to be immutable.

What you could do is to fire events when a property is changed within such objects. Not a perfect solution either.

Documentation is probably the most pragmatic solution ;)

paul
+4  A: 

It depends on the context. If the list is intended to be mutable, there is no point in cluttering up the API of the main class with methods to mutate it when List has a perfectly good API of its own.

However, if the main class can't cope with mutations, then you'll need to return an immutable list - and the entries in the list may also need to be immutable themselves.

Don't forget, though, that you can return a custom List implementation that knows how to respond safely to mutation requests, whether by firing events or by performing any required actions directly. In fact, this is a classic example of a good time to use an inner class.

Bill Michell
A: 

When I was starting out I was still heavily under the influence of HIDE YOUR DATA OO PRINCIPALS LOL. I would sit and ponder what would happen if somebody changed the state of one of the objects exposed by a property. Should I make them read only for external callers? Should I not expose them at all?

Collections brought out these anxieties to the extreme. I mean, somebody could remove all the objects in the collection while I'm not looking!

I eventually realized that if your objects' hold such tight dependencies on their externally visible properties and their types that, if somebody touches them in a bad place you go boom, your architecture is flawed.

There are valid reasons to make your external properties readonly and their types immutable. But that is the corner case, not the typical one, imho.

Will
Data hiding isn't only about preventing other objects from changing your variables - it's about making sure users of your class aren't affected by a change of internal representation. Exposing your internal also prevents you adding actions to be done when members are modified.
DJClayworth
+1  A: 

Your first imperative should be to follow the Law of Demeter or ‘Tell don't ask’; tell the object instance what to do e.g.

contact.print( printer ) ;  // or
contact.show( new Dialog() ) ; // or
contactList.findByName( searchName ).print( printer ) ;

Object-oriented code tells objects to do things. Procedural code gets information then acts on that information. Asking an object to reveal the details of its internals breaks encapsulation, it is procedural code, not sound OO programming and as Will has already said it is a flawed design.

If you follow the Law of Demeter approach any change in the state of an object occurs through its defined interface, therefore side-effects are known and controlled. Your problem goes away.

Martin Spamer
+2  A: 

In the particular case of a Collection, List, Set, or Map in Java, it is easy to return an immutable view to the class using return Collections.unmodifiableList(list);

Of course, if it is possible that the backing-data will still be modified then you need to make a full copy of the list.

Kip
A: 

First of all, setters and getters are an indication of bad OO. Generally the idea of OO is you ask the object to do something for you. Setting and getting is the opposite. Sun should have figured out some other way to implement Java beans so that people wouldn't pick up this pattern and think it's "Correct".

Secondly, each object you have should be a world in itself--generally, if you are going to use setters and getters they should return fairly safe independent objects. Those objects may or may not be immutable because they are just first-class objects. The other possibility is that they return native types which are always immutable. So saying "Should setters and getters return something immutable" doesn't make too much sense.

As for making immutable objects themselves, you should virtually always make the members inside your object final unless you have a strong reason not to (Final should have been the default, "mutable" should be a keyword that overrides that default). This implies that wherever possible, objects will be immutable.

As for predefined quasi-object things you might pass around, I recommend you wrap stuff like collections and groups of values that go together into their own classes with their own methods. I virtually never pass around an unprotected collection simply because you aren't giving any guidance/help on how it's used where the use of a well-designed object should be obvious. Safety is also a factor since allowing someone access to a collection inside your class makes it virtually impossible to ensure that the class will always be valid.

Bill K
"setters and getters are an indication of bad OO" - that really is, quite frankly, completely untrue.
Calanus
Although it is often debated, it is not clearly untrue, and as you start to really understand OO, you realize it's actually a good indicator of a problem (Overuse, that is). In OO you ask an object to do something with it's own data, hence needing to access data externally indicates that the code accessing the data is doing it wrong, it should instead be passing data in and asking that object to operate on it's own data with it's own method. This is not 100%, but it's a valid goal.
Bill K
Also, it's kind of funny how people have an emotional reaction to this concept--since it's the way they learned "OO", they can't imagine it being incorrect. I'm not excluding myself, I had to think about this for a few days before I was sure that designing without properties was better--but I still find it amusing how the answer is always "That's not right" with no explanation or backing--reference perhaps. Anything but "I know it because I feel it".
Bill K
+2  A: 

Joshua Bloch in his excellent "Effective Java" book says that you should ALWAYS make defensive copies when returning something like this. That may be a little extreme, especially if the ContactDetails objects are not Cloneable, but it's always the safe way. If in doubt always favour code safety over performance - unless profiling has shown that the cloneing is a real performance bottleneck.

There are actually several levels of protection you can add. You can simply return the member, which is essentially giving any other class access to the internals of your class. Very unsafe, but in fairness widely done. It will also cause you trouble later if you want to change the internals so that the ContactDetails are stored in a Set. You can return a newly-created list with references to the same objects in the internal list. This is safer - another class can't remove or add to the list, but it can modify the existing objects. Thirdly return a newly created list with copies of the ContactDetails objects. That's the safe way, but can be expensive.

I would do this a better way. Don't return a list at all - instead return an iterator over a list. That way you don't have to create a new list (List has a method to get an iterator) but the external class can't modify the list. It can still modify the items, unless you write your own iterator that clones the elements as needed. If you later switch to using another collection internally it can still return an iterator, so no external changes are needed.

DJClayworth
and if the iterator implements the remove method, it can modify the original list as well...
Nicolas