0

I am in process of learning immutability but I am not able to exactly digest how this works. So in order for me to understand immutability, I created a test program.

The funtion getArray(Box b) will make an ArrayList of Box objects.

    Expected output:    Actual output:

    Output              Output
    a is 5              a is 5
    b is 10             b is 10

    Output              Output
    a is 0              a is 4
    b is 0              b is 40

    Output              Output
    a is 1              a is 4
    b is 10             b is 40

    Output              Output
    a is 2              a is 4
    b is 20             b is 40

    Output              Output
    a is 3              a is 4
    b is 30             b is 40

    Output              Output
    a is 4              a is 4
    b is 40             b is 40

Logic:

public class Box {

    static int a;
    static int b;

    public Box() {
        a = 5;
        b = 10;
    }

    public int getA() {
        return a;
    }

    public void setA(int x) {
        a = x;
    }

    public int getB() {

        return b;
    }

    public void setB(int x) {
        b = x;
    }

    public void display() {
        System.out.println("Output");
        System.out.println("a is " + a);
        System.out.println("b is " + b);
        System.out.println();

    }
}

Main Class

import java.util.ArrayList;

public class Check {

    public static void main(String[] args) {

        Box b = new Box();
        b.display();

        ArrayList<Box> arr2 = new ArrayList<Box>();

        arr2 = getArray(b);

        for (int i = 0; i < arr2.size(); i++) {
            arr2.get(i).display();
        }

    }

    public static ArrayList<Box> getArray(Box b) {

        ArrayList<Box> arr = new ArrayList<Box>();
        for (int i = 0; i < 5; i++) {
            b.setA(i);
            b.setB(i * 10);
            arr.add(b);
        }
        return arr;

    }

}

How do I change the logic in such a way that I get the desired output? How do we decide how and where to edit the code to ensure immutability?

Reinstate Monica
  • 2,767
  • 3
  • 31
  • 40
Apollo
  • 39
  • 1
  • 2
  • 10
  • 1
    ...removing the `static` keyword from your variables `a` and `b` declarations? – FranMowinckel Feb 07 '16 at 11:17
  • also remove setter for variables see below link for condition http://www.javatpoint.com/how-to-create-immutable-class – Musaddique S Feb 07 '16 at 11:18
  • @FranMowinckel : That alone does not help. Tried that. – Apollo Feb 07 '16 at 11:19
  • @TipuSultan: What if you need setters? Instead of changing the functionality, there must be a cleaner way to incorporate immutability here. – Apollo Feb 07 '16 at 11:21
  • This is kind of confusing (not sure what your code has to do with immutability), but it looks like your biggest issue is that Box.a and Box.b are `static` - meaning they're effectively global variables - caling setA() changes a for every Box in the list! – aro_tech Feb 07 '16 at 11:22
  • @Apollo it doesn't help because you're reusing the same object, create a new instance. – FranMowinckel Feb 07 '16 at 11:22
  • try to return new object instead of updating values in current object – Musaddique S Feb 07 '16 at 11:23

2 Answers2

0

This would be an immutable:

public final class Box {
   final int a;
   final int b;

   public Box(int a, int b) {
      this.a = a;
      this.b = b;
   }
}

And then your array method would be:

public static ArrayList<Box> getArray(Box b) {

   ArrayList<Box> arr = new ArrayList<Box> ();
   for(int i =0 ;i <5; i++) {
      arr.add(new Box(i, i*10));
   }
   return arr;

}

The data members are declared final because they're immutable, and so getters are pointless and setters just make no sense.

The class is declared final so you cannot subclass it.

FranMowinckel
  • 4,233
  • 1
  • 30
  • 26
  • Thanks for the clarification! – Apollo Feb 07 '16 at 11:37
  • 1
    *"so getters are pointless"* in this example you don't need getters. However in general I do not agree. (See http://stackoverflow.com/questions/14272425/why-continue-to-use-getters-with-immutable-objects ) – fabian Feb 07 '16 at 11:40
  • 1
    @fabian, that's a long discussion. However, there's an overhead of using a function for just returning a simple `int` and more if it's declared as final. BTW, this is common practice http://developer.android.com/intl/es/reference/android/util/Pair.html – FranMowinckel Feb 07 '16 at 11:46
  • @JanusVarmarken I disagree, just see the link above your comment, they're `public` and `final`. You use a getter if you want to hide your implementation (i.e. returning the super class `Number` instead of `Integer`), track or log when someone uses the variable, transform it (i.e. stored as celsius and return fahrenheit...), but they're not always necessary IMHO. – FranMowinckel Feb 07 '16 at 12:03
  • 1
    As the fields in this example are package-private, it is reasonable to leave out the extra boilerplate required by getters. However, for public fields one should use getters in order to avoid exposing the internal representation of the class as part of the public API. This allows you to change the internal representation of your class without breaking existing client code. Once you make a class or a field public, you're committed to keep it so forever. This is Bloch's words, I don't have the book here so I can't refer the exact item. – Janus Varmarken Feb 07 '16 at 12:04
  • 1
    @FrankMowinckel sorry I accidentally hit enter before finishing my comment. To address your follow up comment I don't think linking an example class from a public api serves as an argument. The Java standard library has a lot of flawed classes, but they cannot be removed because they're part of a public api – Janus Varmarken Feb 07 '16 at 12:09
  • @JanusVarmarken it's a valid example of common practice. BTW, exposing the internal representation is hiding the implementation as I've just commented and I agree. But this is not the case, we have primitive values and a getter is just superfluous. – FranMowinckel Feb 07 '16 at 12:14
  • 1
    @JanusVarmarken the book is *Effective Java -2nd Edition* (BTW great book +1), you're looking for pages 71-72 . Though the author is clearly against direct access to fields, in his words there are 2 exceptions: first, as you mention in private packages or nested classes, but he also says *it's less harmful to expose for public classes to expose immutable fields* and doesn't provide any argument against. – FranMowinckel Feb 07 '16 at 20:31
  • @FranMowinckel yeah exactly. I still don't have access to the book, but I think you've found the part which I was referring to. – Janus Varmarken Feb 08 '16 at 13:24
0

In short, an immutable object is an object whose state cannot be modified after it's created. Your immutable Box object would look like this:

public final class Box {

    private final int a;
    private final int b;

    public Box(int a, int b) {
        this.a = a;
        this.b = b;
    }

    public int getA() {
        return a;
    }

    public int getB() {
        return b;
    }

    public void display() {
        System.out.println("Output");
        System.out.println("a is " + a);
        System.out.println("b is " + b);
        System.out.println();
    }

}

Notice that the variables a and b are assigned exactly once, during the construction of the Box instance. There are no setters, because Box's immutability means that its state (including variables a and b) will not change over its lifetime.

The final keyword in front of a and b means that you must assign them exactly once. It's actually considered good practice to make all your variables final unless you specifically need them not to be; but for an immutable object it's essential.

You were using the static keyword. Static has nothing to do with immutability. It means the variable is shared among all instances of the Box class. In my example, each Box instance has its own copies of a and b, because I didn't make them static.

To wrap this up, I'll give an example of your main class which has the desired output:

public class Check {

    public static void main(String[] args) {
        final List<Box> arr2 = getArray();
        for (int i = 0; i < arr2.size(); i++) {
            arr2.get(i).display();
        }
    }

    public static ArrayList<Box> getArray() {
        final ArrayList<Box> arr = new ArrayList<>();
        for (int i = 0; i < 5; i++) {
            final Box box = new Box(i, i * 10);
            arr.add(box);
        }
        return arr;
    }

}

Note that a new instance of box is created at every iteration of the loop.

Reinstate Monica
  • 2,767
  • 3
  • 31
  • 40
  • 1
    This is not the right way to implement an immutable object (I mean the class definition), because you can just subclass `Box` override the methods `getA()` and `getB()` and implement `setA()` and `setB()` – FranMowinckel Feb 07 '16 at 11:59
  • @FranMowinckel Ah, thank you, I forgot. I changed it, Box is now final, so it can't be overridden. – Reinstate Monica Feb 07 '16 at 12:03
  • @FranMowinckel, actually, whether the class is final or not doesn't affect its immutability in this case. Even if a subclass would override the getters and introduce setters, it could not modify the state of `Box.a` or `Box.b` after the box is created because those fields are `private`. – Mick Mnemonic Feb 07 '16 at 12:17
  • 1
    @MickMnemonic it wasn't about modifying them, before the edit, you could override the getters to return some other variables (i.e. x and y) – FranMowinckel Feb 07 '16 at 13:08
  • Yes, but strictly speaking nothing you could do in the subclass would make the base class mutable. – Mick Mnemonic Feb 07 '16 at 13:30
  • @MickMnemonic strictly speaking the base class would be already mutable because its members can change after the constructor execution has ended. Provided that we don't consider using reflection or JNI to access the private fields, consider the simple case where inside the display method you type by mistake `System.out.println("a is equals b?: " + (a = b))`. – FranMowinckel Feb 07 '16 at 20:15
  • @FranMowinckel, that is not true because the members are `private final`; you would get a compile error. – Mick Mnemonic Feb 07 '16 at 20:52
  • @MickMnemonic that's my point, immutability is not because they're `private`, it's because they're `final`. And making the class `final` prevents subclasses from compromising this immutable behaviour. – FranMowinckel Feb 07 '16 at 21:05
  • @FranMowinckel, as I mentioned in my first comment, making the class `final` changes nothing from the immutability point-of-view. There is no way that subclasses could "compromise the immutability" because they cannot access `private` members. – Mick Mnemonic Feb 07 '16 at 21:49
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/102853/discussion-between-franmowinckel-and-mick-mnemonic). – FranMowinckel Feb 07 '16 at 21:51