pyndustric icon indicating copy to clipboard operation
pyndustric copied to clipboard

While loops with complex conditions

Open TelosTelos opened this issue 4 years ago • 0 comments

Consider the following while loop:

y = 0
while (y+3)<10:  y+=1

In Python, this would exit the loop once y reaches 7. However, our handling of complex expressions currently compiles this to be equivalent to the following:

y = 0
dummy = y+3
while dummy < 10: y+=1

This loop continues infinitely, since nothing within the loop changes the value of dummy. To get the intuitive expected behavior, we would need to recompute dummy within the loop.

Currently while loops are implemented with a negated test at the beginning (if the condition isn't met skip the loop entirely) and a positive test at the end (if the condition is met, loop back up). In cases where the condition is simple, this double-test versions works correctly and is generally optimal (barring some truly heroic optimizations that would require a lot more code-inspection than we're prepared to do), both in speed and brevity. Problems arise only in the case of complex conditions.

If we continue with a double-test version, to get correct behavior for complex conditions, we'll need to recompute things like dummy in both instances of the test, which quickly stops being optimally short (as soon as setting up the test requires two or more dummy computations, repeating them increases length), though it would still be optimally fast. Alternatively we could go back to a single-test version for complex conditions, which would trade away a bit of speed (adding a single jump-always instruction to each iteration to jump to our single instance of the test) in order to gain brevity (you only need one copy of the code that sets up the test).

As in other speed-vs-brevity tradeoffs, the only case where brevity matters is the case where a program exceeds the 1000-instruction limit and becomes uncompilable. But it'll be quite rare for this to be the straw that breaks the camel's back. So on balance it'd almost always be better to favor speed over brevity, even if doing so requires duplicating the code to set up a complex test. So I guess that's what we should do?

The same problem doesn't afflict if (uses only a single negated test), nor our current quite limited implementation of for (uses a double-test, but the exit condition is always simple), though we might someday consider more sophisticated for loops with more sophisticated exit conditions, in which case the same tradeoff could arise there too.

TelosTelos avatar Jan 22 '21 11:01 TelosTelos