0

I have an eternal discussion in my work about why "error first" is "worng".

In order to ensure what I try to tell with error first is the following code pattern:

if condition:
    raise Error()

code

Instead of if-else approach

if condition:
    code
else:
    raise Error()

I think that the first one (error first) is better because you only check your error conditions, you avoid using else statement, by logical error will be raised and never you execute the code.

But on the other hand, probably race conditions or any strange reason, if you encapsulate the error inside an else you are always are setting the logic, and probably is defensive programming approach in order to avoid errors.

The question is there is any reason beyond its de facto standard (in javascript), or there are any other design reasons.

Edit

Another argument is that if only have one error is not enough to do "error first", but anyway I think that if you select an error template for checking the flow of your code you should following in each place including one error code.

Thanks

2
  • More generally, this is called "Return Early." Aug 30, 2021 at 18:25
  • 1
    Rather than thinking in terms of how many errors, think in terms of what it does to enhance the readability of the code. The error first "do checks - write code" pattern reads as "here's what I expect to be true, these are my assumptions", followed by "here's the logic of the method expressed in a simple and straightforward way". With extensive if-else nesting, on the other hand, you have "partial logic - error check - partial logic - error check - some logic that has to do with code 15 lines above - error check - more partial logic - error check ..." Aug 30, 2021 at 18:48

2 Answers 2

11

I prefer the former, because if there are multiple errors then they are handled one after another without further indentation of the non-error code:

if error-condition1:
    raise Error("1")
if error-condition1:
    raise Error("2")

code

Compare with:

if not error-condition1:
    if not error-condition2:
        code
    else:
        raise Error("2")
else:
    raise Error("1")

Here not only does the regular code get indented twice, but the condition1 and Error("1") get separated further the more "code", and the more error conditions there are.  I also don't like the negation as I'd rather test directly for the error condition than the absence of the error condition.

There is another option, which is to swap the then- and else-parts.

if error-condition1:
    raise Error("1")
else if error-condition2:
    raise Error("2")
else:
    code

This is quite readable, though personally I still prefer the else-less version.

4
  • 3
    As I said, I’ve seen this 20 levels deep…
    – gnasher729
    Aug 30, 2021 at 17:21
  • It’s not only errors, it’s also trivial cases quite often that are handled separately. And sometimes it’s hard cases that are solved trivially by “divide and conquer”, and you only have real code for the medium hard cases.
    – gnasher729
    Sep 2, 2021 at 7:11
  • Not only it is more readable, if you later have to add one more check you do not need to touch the "code" lines to change their indentation level. It saves menial work and the diff in source control (which you are using, right?) will be more compact.
    – Rad80
    Sep 2, 2021 at 9:51
  • Worst, if you have 20 errors, then adding another one after error#12 makes it really hard to find where to put the code handling the error. And if you read the code, try finding the code handling error #7.
    – gnasher729
    Sep 5, 2021 at 11:28
5

I’ve seen code doing a few operations that could all potentially fail, with a 20 times nested if. Inserting another error condition after test #11 was practically impossible.

At some point a code structure that handles one condition after the other in a linear fashion is just better.

Not the answer you're looking for? Browse other questions tagged or ask your own question.