Search code examples
javaarraysmutability

References Mutability in Java summing two vectors


I am new to Java and I am following a class, however in one of the exercises I came up with a doubt when comparing my answer vs. teacher.

Say I have a class that holds as attributes the coefficients of a polynomial and I now want to add two polynomials.

In the teacher solution (method add_1) he makes a copy of the coefficients of both arrays being summed, however from what I understood so far Doubles are immutable, so I assume I don´t need to use a copy, but only address directly (method add_2). I have tested an my values in the array are not mutated, however I wanted to confirm my understanding.

public class Polynomial {

    // coefficient at index k belongs to term x^k
    // consistency: array is always present and contains at least one number (which
    // may be zero)
    private double[] coefficients;

    // --------------------- constructors
    // ----------------------------------------------

    // constructor: zero polynomial
    public Polynomial() {
        coefficients = new double[1];
        coefficients[0] = 0;
    }

    public static Polynomial add_1(Polynomial f, Polynomial g) {        // Option 1
        double[] f_array = f.getCoefficients();//Do I need this copy?
        double[] g_array = f.getCoefficients();//Do I need this copy?
        int n = Math.max(f_array.length, g_array.length); // new array needs to be this long

        double[] target = new double[n];
        // fastest way to do it without if-statements:
        for (int k = 0; k < n; k = k + 1) {
            target[k] = 0;//Zero vector array
        }
        for (int k = 0; k < f_array.length; k = k + 1) {
            target[k] = target[k] + f_array[k];
        }
        for (int k = 0; k < g_array.length; k = k + 1) {
            target[k] = target[k] + g_array[k];
        }

        // Turn array into an object
        Polynomial p = new Polynomial();
        p.setCoefficients(target);
        return p;
    }

    public static Polynomial add_2(Polynomial f, Polynomial g) {        // Option 2
        int n = Math.max(f_array.length, g_array.length); // new array needs to be this long

        double[] target = new double[n];
        // fastest way to do it without if-statements:
        for (int k = 0; k < n; k = k + 1) {
            target[k] = 0;//Zero vector array
        }
        for (int k = 0; k < f.coefficients.length; k = k + 1) {
            target[k] = target[k] + f.coefficients[k];
        }
        for (int k = 0; k < g.coefficients.length; k = k + 1) {
            target[k] = target[k] + g.coefficients[k];
        }

        // Turn array into an object
        Polynomial p = new Polynomial();
        p.setCoefficients(target);
        return p;
    }


    // --------------------- setter / getter methods
    // -----------------------------------

    // setter for coefficients, creates a copy(!) of coefficients and stores it
    public void setCoefficients(double[] coefficients) {
        this.coefficients = new double[coefficients.length];
        for (int k = 0; k < coefficients.length; k = k + 1) {
            this.coefficients[k] = coefficients[k];
        }
    }

    // getter for coefficients, returns a copy(!) of the polynomials coefficients
    public double[] getCoefficients() {
        double[] copy = new double[coefficients.length];
        for (int k = 0; k < coefficients.length; k = k + 1) {
            copy[k] = coefficients[k];
        }
        return copy;
    }

}
  1. Is my method add_2 protected against mutation or is there any reason I should use a copy?

Many thanks


Solution

  • double[] f_array = f.getCoefficients();//Do I need this copy?

    This belies a misunderstanding of java.

    f.getCoefficients() doesn't return a double array. That is impossible; java can only return primitives and references. It returns a reference to a double array.

    No copy of an array is being made here. The only copies java makes implicitly are of references and primitives; any other copying is something you'd have to do explicitly using e.g. a copy() or clone() or Arrays.copyOf invocation. All that you've done here is make a copy of the reference which doesn't matter. f.getCoefficients() already returns a copy of the reference.

    Let me try to explain with an example:

    class Example {
        double[] array = new double[10];
    
        public static void main(String[] args) {
            Example ex = new Example();
            double[] arr = ex.array;
            arr[0] = 1;
            System.out.println(arr[0]);
            System.out.println(ex.array[0]);
            ex.array[0] = 2;
            System.out.println(arr[0]);
            System.out.println(ex.array[0]);
            arr = new double[20];
            arr[0] = 20;
            System.out.println(arr[0]);
            System.out.println(ex.array[0]);
        }
    }
    
    > 1
    > 1
    > 2
    > 2
    > 20
    > 2
    

    Initially there is only one array, and both ex.array and arr are references pointing to this array. arr[0] = is dereferencing the reference and doing an operation on what you find there, thus, whilst arr and ex.array are copies, it's a copy of the same reference, and just like if I make a copy of a treasure map and hand it to you, if you then follow your map, dig down, and steal the treasure, and then later I follow my copy, I find the treasure gone - so it is here: arr[0] = 1 affects the one and only array, and thus printing ex.array[0[] also shows 1.

    Later, with arr = new double[20] we first make a new object (new double[20]) and then assign a reference to this newly created object to arr, which has no effect on ex.array. Thus, now, it's like you have a treasure map to a completely different treasure vs. my ex.array treasure map. Therefore, when you follow your map, dig down, and put a 20 in the box, if I follow my map, I do not see that, hence why the last 2 lines prints 20 and 1, and not 20 and 20.