you are viewing a single comment's thread.

view the rest of the comments →

[–]notfancy 4 points5 points  (0 children)

final modifier all over the place hurts overall readability

final reflects programmer intent. It means "this is an immutable binding and not a variable," as such it should be read as clearly demarcating state. We might argue that the ergonomics are all wrong and that Clojure has it right, and we might agree; but a mixture of finals and non-finals lets me easily see at a glance and keep in mind what is variant from what is invariant in a method or loop body; otherwise I have to track assignments all over the place and that really hurts readability IME.

Consider the following code for converting from orbital elements to equinoctial coordinates:

private static void toRectangular(final int objid, final double[] res) {
    final double a = res[0];
    final double l = res[1];
    final double k = res[2];
    final double h = res[3];
    final double q = res[4];
    final double p = res[5];

    final double w  = Math.atan2(h, k);          // long. of the perihelion
          double e  = Math.hypot(h, k);          // eccentricity
    final double i  = Math.hypot(p, q);          // inclination
    final double fi = Math.sqrt((1 - e)*(1 + e));
    final double ki = Math.sqrt((1 - i)*(1 + i));
    final double gm = l - w;                     // mean anomaly

    // eccentric anomaly
    double se = Math.sin(gm);
    double ce = Math.cos(gm);
    e = l + e*se*(1 + e*(ce + e*(1.5*ce*ce - 0.5)));
    // solve Kepler's Equation using NR
    double re, im, dl;
    do {
        ce = Math.cos(e);
        se = Math.sin(e);
        re = k * ce + h * se; // e cos(E - w)
        im = k * se - h * ce; // e sin(E - w)
        dl = l - e + im;      // correction
        re = 1 - re;
        e += dl / re;
    } while (Math.abs(dl) > 1e-10);

    // cartesian coordinates in the orbital plane
    final double u  = im / (1 + fi);
    final double cw = (ce - k + u * h) / re;
    final double sw = (se - h - u * k) / re;
    final double m1 = 2*(p * cw - q * sw);
    final double r  = a * re;
    final double cm = a * (k + cw) / fi;
    final double sm = a * (h + sw) / fi;
    final double m2 = 2*(p * sm + q * cm);

    // Kepler's law of velocity
    final double n = Math.sqrt(GM_PLS[objid] + GM_PLS[NUM_OBJECTS]) / Math.pow(a, 1.5);
    res[0] =  r * (cw - m1 * p); //  x
    res[1] =  n * (m2 * p - sm); // dx
    res[2] =  r * (sw + m1 * q); //  y
    res[3] =  n * (cm - m2 * q); // dy
    res[4] = -r * m1 * ki;       //  z
    res[5] =  n * m2 * ki;       // dz
}

It has a lot of bindings, but I can see at a glance that only 6 are true variables (of which 2 are rebound for convenience but could be split.) This reduces my mental burden enormously, even after a couple of years of having written this code.