3

I was implementing an immutable class whose structure is as below :

public final class A{ private final B bOb; public A(){ bOb = new B(); } public A(A a){ bOb = new B(a.bOb); } public A addData(Type data){ // Type - Integer,String,char,etc. A newA = new A(this); //making a copy of the object that is calling addData method newA.bOb.add(data); return newA; } } 

Is this implementation correct ? Let's say the object bOb is a list.

3

5 Answers 5

2

It is not totally immutable, since B appears to be mutable itself (via the add method) and A contains an instance of B.

However I think it is effectively immutable (i.e. it behaves as if it was immutable from the perspective of an external observer) providing that all the following are true:

  • new B(B) performs a complete deep copy of B (if not then addData may mutate something within the original B)
  • you aren't leaking references to bOb via any other means
  • the elements added themselves are immutable

You get most of the benefits of immutability from being effectively immutable so I think this design is OK providing Type is immutable - it's fine to mutate an object during it's construction providing it never gets mutated after you pass a reference to someone else. A good example of this is java.lang.String - internally it contains a mutable array that is written to while the String is constructed but never changed after that point.

Sign up to request clarification or add additional context in comments.

11 Comments

Since B in my case is a LinkedList (which is mutable) , and I am doing , bOb = new B(a.bOb); , that is , I am not using any getter for bOb , I am accessing it directly through my object A a , it should be immutable right?
@sTEAK - LinkedList doesn't do a deep clone, so if any of its contents are mutable then you lose your overall immutability. If you stick to immutable contents in the LinkedList then you should be fine - but that rather depends on Type. P.S. might be a good place to use generics :-)
Is there any work-around for adding mutable objects to this ? So that it still stays immutable
@sTEAK. You can't possibly have an immutable object that takes foreign objects and makes its observable state depend in any way on the state of those objects. So the question is still open: does the observable state of your A depend in any way on the state of the objects in the LinkedList?
Defencive copy technique can help you. For example, you can add some interface Copyable<T extends Copyable<T>> wich will have public T getCopy() method. And you class can take this interface as generic parameter and use it for defencive copy. But this solution have disadvatages - only your classes can implement this interface.
|
2

Your implementation:

public A addData(int data){ A newA = new A(this); newA.bOb.add(data); // <--- bOb is mutable return newA; } 

A bOb is being changed, so if you expose any direct access to bOb, it can be changed. (Since you're not exposing anything about bOb, the scenario doesn't make sense.)

Hints:

  • Collections.emptyList() returns an immutable list.
  • Collections.unmodifiableList() returns an immutable shallow-copy of a given list.

Consider this "safer" implementation:

import java.util.*; public final class A<T>{ //T must also be immutable (String, integer, char, ...) private final List<T> list; public A(){ this.list = Collections.emptyList(); } public A(List<T> list){ this.list = Collections.unmodifiableList(list); } public A<T> addData(T data){ List<T> shallowCopy = new ArrayList<T>(this.list); shallowCopy.add(data); return new A<T>(shallowCopy); } public List<T> getItems() { return this.list; } } 

3 Comments

It depends on how new B(a.bOb); is implemented. Or not?
Try Collections.unmodifiableList()... does it still work?
Mutating bOb within the class is usually considered fine as long as the state change is invisible outside of A. See this description of immutable queues in Scala for a similar example.
1

If bOb is a list and it contains mutable content, then not. But it seems that you use only int as content and this solves the problem.

7 Comments

Well B is actually a LinkedList and I am adding a generic value to the list through addData method , so it is not necessarily an int. So you mean to say its not immutable?
For example, if you put mutable content in your bOb (lets say another List), then it can be modified and this will affect A instance state.
But if I am adding an Integer to the list throw the addData method , then ?
Integer is immutable, so your class will be immutable for this type. But if you will use Date,for example, then it can be modified and affect instance state. For example, A a=new A();Date d=new Date();a.addData(d);d.setTime(1L);. In last operator d object will be modified and a object state will be modified too. But this modification will not affect visible state since your class does not have it. This is interesting part -you class does not have visible state, so it is useless, but immutable. If you will share its state (including bob value), then visible state will be affected.
So , effectively is it immutable in all cases?
|
1

In this form, yes, your class is immutable.

However, this is a trivial example and wouldn't actually be useful for anything since you can't access any of the internal data. The thing you need to be careful of is to not let any references to bOb escape from A. If you add a method which returns bOb, you need to return a copy of bOb to avoid accidentally allowing the caller to mutate any of the contents of A.

Comments

0

It depends on how B(B b) constructor works. If it is a copy constructor, it should make a deep copy of b fields. In this case A is immutable.

Instead if the constructor simply take the reference to the same b instance, any change to it will reflect on bOb property, so the A class in not immutable...

1 Comment

well, so using LinkedList(Collection c) you can obtain a new list with the same elements. As you say Type is a primitive type (or a wrapper), so your A class is immutable.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.