Readable Math Code

August 5, 2013 —

Since I've been spending a lot of the day today writing 3D math code in Java (and in a way to keep garbage collection to a minimum) I feel I must rant about this. Anyone not doing game dev work would probably not care at all about this, and on the whole this is nothing new to anyone who writes any math code in Java, but even still... here goes.

<rant>

Java has no operator overloading. The common argument is that it makes code a bit harder to follow and/or it could lead to abuse, such as a case where someone overloads the + operator to something non-obvious.

So, in the first place, what kind of nitwit is writing an operator overload that is doing something non-obvious. I'd argue that anyone who would do this is not someone you'd want writing code in any language anyway. I've never seen someone do this in all my professional time spent writing C# code where operator overloading is allowed. The most "iffy" use of operator overloading I think I've seen is the use of the * operator for calculating the cross-product of two vectors. And to be honest that's really not that bad, even though I'd personally not want to do that.

But no, all these Java people think that this kind of thing is the devil and, my god, why would you want to do that.

So, now we're stuck having to rewrite code like this:

Vector3 intersection = (position - trianglePlane.normal) + velocity * t0;

to this:

Vector3 intersection = new Vector3(position).sub(trianglePlane.normal).add(new Vector3(velocity).scl(t0));

Oh, that's kind of crummy to read, I wonder if we can clean it up?

Vector3 intersection = new Vector3(position)
        .sub(trianglePlane.normal)
        .add(new Vector3(velocity).scl(t0));

Hrm, I don't know if that's any better ... oh wait! I'm allocating two new objects in this calculation and this code needs to run at 60 FPS! Hrm, let's add some pre-allocated objects to the mix and fix that:

...
private Vector3 intersection = new Vector3();
private Vector3 tmp = new Vector3();  // because wtf else do I call this!?

...

tmp.set(velocity)
   .scl(t0);
intersection.set(position)
            .sub(trianglePlane.normal)
            .add(tmp);

// or this if you prefer it to be more compact I guess ...
tmp.set(velocity).scl(t0);
intersection.set(position).sub(trianglePlane.normal).add(tmp);

Hooray?

Holy. Shit. Such unnecessary boilerplate and uglification for something so simple. And don't even get me started on the whole "no allocating stuff on the stack" bullshit.

And yes, this particular case could probably be simplified a slight bit more perhaps-- sure, now let me show you the ~10 other equally as shitty calculations I had to write in other places in my code which aren't so cut-and-dry.

</rant>