Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

This question already has an answer here:

What is the best practice for checking multiple conditions, in no particular order?

The example in question needs to check four distinct conditions, in any order, and fail showing the correct error message.

The examples below use a C-like syntax.

Option 1: Check all at once

This method isn't preferred because the reasons why the condition failed aren't easy to discern.

if (A && B && C && D) {
    // continue here...
} else {
    return "A, B, C, or D failed";
}

Option 2: Nested Conditions

In the past, I used to use nested conditional statements, like so. This can get really confusing.

if (A) {
    if (B) {
        if (C) {
            if (D) {
                // continue here...
            } else {
                return "D failed"
            }
        } else {
            return "C failed";
        }
    } else {
        return "B failed";
    }
} else {
    return "A failed";
}

Option 3: Fail-early

This is the current method I use, which I like to call fail-early. As soon as a "bad" condition is hit, it returns.

if (!A) {
    return "A failed";
}

if (!B) {
    return "B failed";
}

if (!B) {
    return "C failed";
}

if (!D) {
    return "D failed";
}

// continue here...

Option 4: Collect Errors

One last approach I can think of is a sort of collection of errors. If the conditions to test for are completely separate, one might want to use this approach.

String errors = "";
if (!A) {
     errors += "A failed\n";
}

if (!B) {
    errors += "B failed\n";
}

if (!C) {
    errors += "C failed\n";
}

if (!D) {
    errors += "D failed\n";
}

if (errors.isEmpty()) {
    // continue here...
} else {
    return errors;
}

What are the best practices for checking multiple conditions? In terms of expectations, it ideally behaves like example 4, where details of all the failures are returned.

share|improve this question

marked as duplicate by gnat, Martijn Pieters, Oleksi, Mark Booth, Kilian Foth Mar 20 '13 at 10:04

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

    
You did not mention one important thing which may have influence: are A, B, C, and D preconditions, to be checked before a particular operation will be executed, or are those results of 4 operations OpA(), OpB(), ... where the call to OpB() may not make sense if OpA() has failed. This will also make a difference. –  Doc Brown Mar 20 '13 at 8:36

3 Answers 3

The answer is... it depends.

Does any one of A, B, C, or D cause it not to work? Does checking for A and failing make checking for B, C, or D impractical or redundant? Is it useful to report the collection of errors that were reported or just the first one detected?

Each of the options presented has its use in the proper situation. There is no one error handling approach to rule them all.

share|improve this answer
1  
That's a good answer. Are there any other approaches to this problem? –  Redandwhite Mar 19 '13 at 20:54
    
@Redandwhite not particularly. You are either returning 0 (option #1), 1 (option #2 and #3) or many (option #4) pieces of information about the errors. Each has its associated data structure with it (boolean, value, collection)... and that really about covers the range of things you can return back about validation. –  MichaelT Mar 19 '13 at 21:02
    
Thanks! So to clarify, in terms of syntax, there aren't any 'cleaner' alternatives for each of the possible returns? –  Redandwhite Mar 19 '13 at 21:22
    
@Redandwhite there may be specific situations where a combination of 3 and 4 present itself as cleaner, but in the general case... I don't see any that are archetypal examples of other ways to handle errors in that format. When one goes to goto allowed (goto error handling), or exceptions (nested try-finally blocks) there are some other structures that crop up, but those are more for exceptional cases. –  MichaelT Mar 19 '13 at 21:30

It really depends on what kind of information you want back from the function. Let's break down what every option gives you :

  1. You don't care which condition fails, you only want to know if they all succeed or not.

  2. Clearly out of the way. Very bad formatting and readability because of code nesting. Does the same thing as #3 but uglier.

  3. You get to know the first condition that failed.

  4. You get to know every condition that failed.

Now it's really up to you to judge which option is the best, depending on the context and what information you really need.

share|improve this answer
    
Thanks. I was curious if there any more approaches to this problem. –  Redandwhite Mar 19 '13 at 20:54
2  
Option 4 is nice for user-facing messages, say on a web form. You entered these fields incorrectly. Otherwise, I find myself using option 1 most. –  Snowman Mar 19 '13 at 23:29

The answer depends hugely on what language you're using and what you are going to do as a consequence of the errors.

For example, in Scala, and assuming that I want to report every error so that they can all be fixed at once, I'd probably do something like

val (yes, no) = List(
  (A, "A failed"),
  (B, "B failed"),
  (C, "C failed"),
  (D, "D failed")
).partition(_._1)
if (!no.isEmpty) Some(no.map(_._2)) else None

where I first group my conditions and error messages, then sort them into two groups--the successes and the failures--and return those error messages if there was something, and otherwise return a sentinel value saying--in this case--that everything's okay.

But this relies critically on Scala's ability to quickly group and map and manipulate collections and containers. In Java, I would write the exact same code in the more verbose (and less convenient to check, as I now need to query errors.size() to know whether I have failed anything):

ArrayList<String> errors = new ArrayList<String>();
if (!A) errors.add("A failed");
if (!B) errors.add("B failed");
if (!C) errors.add("C failed");
if (!D) errors.add("D failed");
return errors;

If we only need the first error, in Java I'd do fail-fast while in Scala I might

List(A,B,C,D).zipWithIndex.find(!_._1).foreach{ x => return x._2 }

assuming I was okay with the number of the item that went bad as a return code.

So the answer is really: you've got the important different styles, but how exactly to implement them most efficiently/least painfully is going to depend a lot on your tools.

share|improve this answer

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