views:

758

answers:

13

In an answer (by S.Lott) to a question about Python's try...else statement:

Actually, even on an if-statement, the else: can be abused in truly terrible ways creating bugs that are very hard to find. [...]

Think twice about else:. It is generally a problem. Avoid it except in an if-statement and even then consider documenting the else- condition to make it explicit.

Is this a widely held opinion? Is else considered harmful?

Of course you can write confusing code with it but that's true of any other language construct. Even Python's for...else seems to me a very handy thing to have (less so for try...else).

+21  A: 

S.Lott has obviously seen some bad code out there. Haven't we all? I do not consider else harmful, though I've seen it used to write bad code. In those cases, all the surrounding code has been bad as well, so why blame poor else?

dwc
Agreed - it's too easy to blame the tools and not the person using them
Mike Robinson
+14  A: 

No it is not harmful, it is necessary.

There should always be a catch-all statement. All switches should have a default. All pattern matching in an ML language should have a default.

The argument that it is impossible to reason what is true after a series of if statements is a fact of life. The computer is the biggest finite state machine out there, and it is silly to enumerate every single possibility in every situation.

If you are really afraid that unknown errors go unnoticed in else statements, is it really that hard to raise an exception there?

Unknown
Disagree. There should *never* be a catch-all IF you can't actually articulate the logic that leads to the catchall. If you can't define exactly what condition leads to the catch-all, you have bugs.
S.Lott
@S.Lott so instead of catching unknown conditions in the else statement, you would let it fall through and execute whatever code is left in the function?
Unknown
Personally, I'd refactor the code until it no longer had code paths in which the programmer is basically saying "I don't know how I got here, but I'll do something anyway. It'll probably work". Whether that "something" is to raise ProgrammerNotSmartEnoughException, or to carry on executing the rest of the program, you have a problem. Perhaps a smaller problem in the case of the exception, but still a problem.
Steve Jessop
+4  A: 

To me, the whole concept of certain popular language constructs being inherently bad is just plain wrong. Even goto has its place. I've seen very readable, maintainable code by the likes of Walter Bright and Linus Torvalds that uses it. It's much better to just teach programmers that readability counts and to use common sense than to arbitrarily declare certain constructs "harmful".

dsimcha
And I think calling else "harmful" is going way too far. I only said to think about and make the condition explicit. I didn't say "never use it".
S.Lott
+6  A: 

Saying that else is considered harmful is a bit like saying that variables or classes are harmful. Heck, it's even like saying that goto is harmful. Sure, things can be misused. But at some point, you just have to trust programmers to be adults and be smart enough not to.

What it comes down to is this: if you're willing to not use something because an answer on SO or a blog post or even a famous paper by Dijkstra told you not to, you need to consider if programming is the right profession for you.

Jason Baker
+1: yes, even goto still has a place. When "GOTO Considered Harmful" was written the rant was needed, but it seems the lessons were learned.
dwc
No: else is not the same level of harm. Else is intentionally vague. It's CAN be a sloppy way of saying "I can't reason out the conditions, so I'll just hope that the right ones fall into my else". If you're doing that kind of sloppy non-thinking, you're writing intentional bugs.
S.Lott
@S.Lott - I think you're missing my point. My point is that people need to get away from the "x is bad, don't use it" mentality. ESPECIALLY in terms of language constructs.
Jason Baker
+7  A: 

I wouldn't say it is harmful, but there are times when the else statement can get you into trouble. For instance, if you need to do some processing based on an input value and there are only two valid input values. Only checking for one could introduce a bug. eg:

The only valid inputs are 1 and 2:

if(input == 1)
{
   //do processing
   ...
}
else
{
   //do processing 
   ...
}

In this case, using the else would allow all values other than 1 to be processed when it should only be for values 1 and 2.

Mr. Will
in this case you should have done else if(input == 2) and then have an else { throw InvalidInput }
Unknown
Exactly. I've been bit by this bug many times when trying to do maintenance on legacy apps. I try to use else simply to throw exceptions for invalid data, that is unless all I need is a single if statement.
Mr. Will
nan, I would just have else if(input==2) and nothing else, so nothing will happen if input is not 1 or 2... so good example +1
TStamper
It's hardly else's fault that the programmer's logic is faulty. '1 v 2 => Processing' is not logically equivalent to '1 v ~1 => Processing'. Programmer's really do need to take some binary/propositional logic, might as well blame boolean values for these sorts of mistakes.
Esteban Brenes
A: 

In the example posited of being hard to reason, it can be written explicitly, but the else is still necessary. E.g.

if a < 10:       
    # condition stated explicitly   
elif a > 10 and b < 10:       
    # condition confusing but at least explicit   
else:       
    # Exactly what is true here?       
    # Can be hard to reason out what condition is true

Can be written

if a < 10:       
    # condition stated explicitly   
elif a > 10 and b < 10:       
    # condition confusing but at least explicit   
elif a > 10 and b >=10:
    # else condition
else:   
    # Handle edge case with error?
Nat
-1 : The second version is no clearer than the first. Without knwoing the reason for the code, either could be valid.
Jon Cage
It makes all options explicit, the else clause would only get called when there is a bug within the logic of the first three options. still a pretty meaningless example sure.
Nat
Consider the maintenance programmer who changes some of the clauses but doesn't think through the (obscure) logic. Now the "edge case" suddenly starts happening because of shoddy code changes. Tossing the edge case into an else will lead to mysteries. Handling the unthinkable error (in example 2) will expose the maintenance mistake immediately.
S.Lott
+2  A: 

Else is most useful when documenting assumptions about the code. It ensures that you have thought through both sides of an if statement.

Always using an else clause with each if statement is even a recommended practice in "Code Complete".

Even Mien
Yeah, I came to think of that statement in Code Complete aswell!I feel a bit damaged for remembering that one!
kotlinski
A: 

The rationale behind including the else statement (of try...else) in Python in the first place was to only catch the exceptions you really want to. Normally when you have a try...except block, there's some code that might raise an exception, and then there's some more code that should only run if the previous code was successful. Without an else block, you'd have to put all that code in the try block:

try:
    something_that_might_raise_error()
    do_this_only_if_that_was_ok()
except ValueError:
    # whatever

The issue is, what if do_this_only_if_that_was_ok() raises a ValueError? It would get caught by the except statement, when you might not have wanted it to. That's the purpose of the else block:

try:
    something_that_might_raise_error()
except ValueError:
    # whatever
else:
    do_this_only_if_that_was_ok()

I guess it's a matter of opinion to some extent, but I personally think this is a great idea, even though I use it very rarely. When I do use it, it just feels very appropriate (and besides, I think it helps clarify the code flow a bit)

David Zaslavsky
I can't help the feeling that if you want `do_this_only_if_that_was_ok` to be called either way and you think it could raise a value error, it would be clearer to add it to a seperate statement (assuming you're trying to seperate them out that is).
Jon Cage
But I don't want it to be called either way (i.e. whether the exception is raised or not), I want it to only be called if something_that_might_raise_error() didn't raise an error. And if do_this_only_if_that_was_ok() raises an error, it should not be caught (at least not at this level). I don't see any way to do that other than the way I've written here.
David Zaslavsky
A: 

Au contraire... In my opinion, there MUST be an else for every if. Granted, you can do stupid things, but you can abuse any construct if you try hard enough. You know the saying "a real programer can write FORTRAN in every language".

What I do lots of time is to write the else part as a comment, describing why there's nothing to be done.

Dave Vogt
+1  A: 

Seems to me that, for any language and any flow-control statement where there is a default scenario or side-effect, that scenario needs to have the same level of consideration. The logic in if or switch or while is only as good as the condition if(x) while(x) or for(...). Therefore the statement is not harmful but the logic in their condition is.

Therefore, as developers it is our responsibility to code with the wide scope of the else in-mind. Too many developers treat it as a 'if not the above' when in-fact it can ignore all common sense because the only logic in it is the negation of the preceding logic, which is often incomplete. (an algorithm design error itself)

I don't then consider 'else' any more harmful than off-by-ones in a for() loop or bad memory management. It's all about the algorithms. If your automata is complete in its scope and possible branches, and all are concrete and understood then there is no danger. The danger is misuse of the logic behind the expressions by people not realizing the impact of wide-scope logic. Computers are stupid, they do what they are told by their operator(in theory)

I do consider the try and catch to be dangerous because it can negate handling to an unknown quantity of code. Branching above the raise may contain a bug, highlighted by the raise itself. This is can be non-obvious. It is like turning a sequential set of instructions into a tree or graph of error handling, where each component is dependent on the branches in the parent. Odd. Mind you, I love C.

Aiden Bell
A: 

I think the point with respect to try...except...else is that it is an easy mistake to use it to create inconsistent state rather than fix it. It is not that it should be avoided at all costs, but it can be counter-productive.

Consider:

try:
    file = open('somefile','r')
except IOError:
    logger.error("File not found!")
else:
    # Some file operations
    file.close()
# Some code that no longer explicitly references 'file'

It would be real nice to say that the above block prevented code from trying to access a file that didn't exist, or a directory for which the user has no permissions, and to say that everything is encapsulated because it is within a try...except...else block. But in reality, a lot of code in the above form really should look like this:

try:
    file = open('somefile','r')
except IOError:
    logger.error("File not found!")
    return False
# Some file operations
file.close()
# Some code that no longer explicitly references 'file'

You are often fooling yourself by saying that because file is no longer referenced in scope, it's okay to go on coding after the block, but in many cases something will come up where it just isn't okay. Or maybe a variable will later be created within the else block that isn't created in the except block.

This is how I would differentiate the if...else from try...except...else. In both cases, one must make the blocks parallel in most cases (variables and state set in one ought to be set in the other) but in the latter, coders often don't, likely because it's impossible or irrelevant. In such cases, it often will make a whole lot more sense to return to the caller than to try and keep working around what you think you will have in the best case scenario.

David Berger
+4  A: 

If you write:

if foo:
    # ...
elif bar:
    # ...
# ...

then the reader may be left wondering: what if neither foo nor bar is true? Perhaps you know, from your understanding of the code, that it must be the case that either foo or bar. I would prefer to see:

if foo:
    # ...
else:
    # at this point, we know that bar is true.
    # ...
# ...

or:

if foo:
    # ...
else:
    assert bar
    # ...
# ...

This makes it clear to the reader how you expect control to flow, without requiring the reader to have intimate knowledge of where foo and bar come from.

(in the original case, you could still write a comment explaining what is happening, but I think I would then wonder: "Why not just use an else: clause?")

I think the point is not that you shouldn't use else:; rather, that an else: clause can allow you to write unclear code and you should try to recognise when this happens and add a little comment to help out any readers.

Which is true about most things in programming languages, really :-)

John Fouhy
+1: if foo: something; else: assert bar; something else. Make it explicit in some way.
S.Lott
A: 

There is a so called "dangling else" problem which is encountered in C family languages as follows:

if (a==4)
if (b==2)
printf("here!");
else
printf("which one");

This innocent code can be understood in two ways:

if (a==4)
    if (b==2)
        printf("here!");
    else
        printf("which one");

or

if (a==4)
    if (b==2)
        printf("here!");
else
    printf("which one");

The problem is that the "else" is "dangling", one can confuse the owner of the else. Of course the compiler will not make this confusion, but it is valid for mortals.

Thanks to Python, we can not have a dangling else problem in Python since we have to write either

if a==4:
    if b==2:
        print "here!"
else:
    print "which one"

or

if a==4:
    if b==2:
        print "here!"
    else:
        print "which one"

So that human eye catches it. And, nope, I do not think "else" is harmful, it is as harmful as "if".

Caglar Toklu