Short-circuit Logic

Steven D'Aprano steve+comp.lang.python at pearwood.info
Thu May 30 12:40:52 EDT 2013


On Fri, 31 May 2013 01:56:09 +1000, Chris Angelico wrote:

> On Fri, May 31, 2013 at 1:02 AM, Ethan Furman <ethan at stoneleaf.us>
> wrote:
>> On 05/30/2013 05:58 AM, Chris Angelico wrote:
>>> If you iterate from 1000 to 173, you get nowhere. This is the expected
>>> behaviour; this is what a C-style for loop would be written as, it's
>>> what range() does, it's the normal thing. Going from a particular
>>> starting point to a particular ending point that's earlier than the
>>> start results in no iterations. The alternative would be an infinite
>>> number of iterations, which is far far worse.
>>
>> If the bug is the extra three zeros (maybe it should have been two),
>> then silently skipping the loop is the "far, far worse" scenario.  With
>> the infinite loop you at least know something went wrong, and you know
>> it pretty darn quick (since you are testing, right? ;).
> 
> You're assuming you can casually hit Ctrl-C to stop an infinite loop,
> meaning that it's trivial. It's not. Not everything lets you do that; or
> possibly halting the process will halt far more than you intended. What
> if you're editing live code in something that's had uninterrupted uptime
> for over a year? 

Then more fool you for editing live code.

By the way, this is Python. Editing live code is not easy, if it's 
possible at all.

But even when possible, it's certainly not sensible. You don't insist on 
your car mechanic giving your car a grease and oil change while you're 
driving at 100kmh down the freeway, and you shouldn't insist that your 
developers modify your code while it runs.

In any case, your arguing about such abstract, hypothetical ideas that, 
frankly, *anything at all* might be said about it. "What if Ctrl-C causes 
some great disaster?" can be answered with an equally hypothetical "What 
if Ctrl-C prevents some great disaster?"


> Doing nothing is much safer than getting stuck in an
> infinite loop. 

I disagree. And I agree. It all depends on the circumstances. But, given 
that we are talking about Python where infinite loops can be trivially 
broken out of, *in my experience* they are less-worse than silently doing 
nothing.

I've occasionally written faulty code that enters an infinite loop. When 
that happens, it's normally pretty obvious: something which should 
complete in a millisecond is still running after ten minutes. That's a 
clear, obvious, *immediate* sign that I've screwed up, which leads to me 
fixing the problem.

On the other hand, I've occasionally written faulty code that does 
nothing at all. The specific incident I am thinking of, I wrote a bunch 
of doctests which *weren't being run at all*. For nearly two weeks (not 
full time, but elapsed time) I was developing this code, before I started 
to get suspicious that *none* of the tests had failed, not even once. I 
mean, I'm not that good a programmer. Eventually I put in some deliberate 
errors, and they still didn't fail. 

In actuality, nearly every test was failing, my entire code base was 
rubbish, and I just didn't know it.

So, in this specific case, I would have *much* preferred an obvious 
failure (such as an infinite loop) than code that silently does the wrong 
thing.

We've drifted far from the original topic. There is a distinct difference 
between guarding against inaccuracies in floating point calculations:

# Don't do this!
total = 0.0
while total != 1.0:
    total += 0.1

and guarding against typos in source code:

total = 90  # Oops, I meant 0
while total != 10:
    total += 1

The second case is avoidable by paying attention when you code. The first 
case is not easily avoidable, because it reflects a fundamental 
difficulty with floating point types.

As a general rule, "defensive coding" does not extend to the idea of 
defending against mistakes in your code. The compiler, linter or unit 
tests are supposed to do that. Occasionally, I will code defensively when 
initialising tedious data sets:

prefixes = ['y', 'z', 'a', 'f', 'p', 'n', 'µ', 'm', 
            'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
assert len(prefixes) == 16


but that's about as far as I go.


-- 
Steven



More information about the Python-list mailing list