I was writing a 2D curve algorithm and had a bit of code that effectively did a summation a la:
for (i=0, end=...; i<end; i++) {
value += coefficients[i] * expensiveToCalculateValue(i);
}
where the value coefficients[i]
was zero for some of of the iteration steps. Since zero times something is still zero (at least under plain arithmetic rules), I figured I could optimise this code significantly by first checking if coefficients[i]
is zero, and if so, just continue
to the next iteration. Added, sorted, works brilliantly.
But this leaves a question: why is this not done for me? This is not some creative niche version of multiplication, it's plain arithmetic. Virtually all languages short-circuit binary OR and AND operations if an operand is found that will make the result invariant from that point on, so why is the arithmetic multiplication by zero not equally short-circuited?
I tried running this code (modified for synax) in Java, PHP, JavaScript, Perl, Python, C++, and even had a look at what Prolog did, but none of them realise that once they see "zero times ..." they don't have to evaluate the potentially expensive second (or third, fourth, etc) term:
printed = 0;
function veryExpensive() {
print "oh god this costs so much, x" + (printed++);
return 0;
}
value = 0 * veryExpensive() * veryExpensive() * veryExpensive()
All of them just end up running veryExpensive()
three times.
Now, I understand that you can -if you're that kind of person- write your veryExpensive
function to do administrative overhead work based on the fact that you can rely on it being executed despite its result not contributing to the arithmetic expression (if you do that, you're probably abusing a language, but everyone loves sneaky ninja code at some point during their programming life), but you only do that because you know the language happens to funnily not optimize for this case. You wouldn't exactly be hampered in your code expressiveness if the language optimized the arithmetic evaluation for you.
So: is there some historical precedent that has caused a boatload of currently used languages to optimise for "true OR ..." and "false AND ..." but not "zero TIMES ..."? Why do we optimise for binary operations, but not for MUL 0? (And if we're lucky, someone has a fascinating tale to tell on why we now don't short-circuit)
update
Both John Skeet and Nik Bougalis give good arguments on why optimizing this in an extant language will lead to problems, but Nik's answer lines up with the question a bit more, so I marked his answer as the "correct" one. That said, they cover different aspects of the same problem so the real answer is a combination of the two.