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:

Should you throw an exception if a method's input values are out of range? eg

//no imaginary numbers
public int MySquareRoot(int x)
{
    if (x<0)
    {
    throw new ArgumentOutOfBoundsException("Must be a non-negative integer"); 
    }

    //our implementation here 

}

Now this method should never be called with a non-negative number, but hey programmers make mistakes. Is throwing exceptions here the right thing to do?

share|improve this question

marked as duplicate by Yannis Rizos May 14 at 20:37

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.

28  
What else would an ArgumentsOutOfBoundsException be intended for? –  Kilian Foth May 13 at 8:11
7  
1) What alternative do you propose? 2) Why would the square root function return an integer? –  200_success May 13 at 9:44
6  
If the language supports it (ie: c#), you can use uint –  RMalke May 13 at 12:23
1  
Would an IllegalArgumentException be sufficent here? –  Robert Niestroj May 13 at 13:18
2  
throw new QuestionTooVagueException("Specify a language when asking questions about best practices."); –  Caleb May 13 at 17:52

6 Answers 6

Yes, I believe you should throw an exception, to help your fellow programmers notice the error at compile-time, by also adding throws ArgumentOutOfBoundsException in your method declaration.

That is, unless you use imaginary numbers in your project, where -1 is a perfectly valid argument for your square root method. :)

share|improve this answer
4  
It's worth noting that not all languages allow specifying exceptions in method signatures. –  DougM May 13 at 12:53
1  
@DougM I can think of only one that does: Java. And possibly Ada. –  Michael Kjörling May 13 at 13:01
6  
In which language is throwing an exception "the error at compile-time"? –  BЈовић May 13 at 14:46
2  
@BЈовић, checked exceptions in Java must be acknowledged or the compiler fails with an error. Although Java's argument exception (IllegalArgumentException) is not a checked exception (and rightly so), so I'm not sure what he is referring to. –  Phil K May 13 at 15:09
1  
@Voo That's not checked in nearly the same way though. C++ just exits hard if you throw an exception you said you wouldn't, which is usually the opposite of what you want to happen with checked failures! –  jozefg May 13 at 17:39

If you can code your method or its signature in such a way that the exception condition cannot happen, doing so is arguably the best approach.

For example, with the particular example you bring up, does your language have an unsigned integer data type with an appropriate range? If so, just use that one rather than a corresponding signed integer type and throwing an exception for any value passed in that is less than 0. In that case, a negative value cannot be used in that position in a well-formed program; the compiler will catch the mistake long before runtime, and at the very least issue a warning (for signed/unsigned type use mismatch), unless you go out of your way to explicitly bypass that safety net; and if you're forcing a signed variable into a function whose method signature says unsigned integer only without making sure that the value is within an acceptable range for that function, then I'd argue that the programmer doing so deserves to get an exception thrown in their face.

As another example, if only a reasonably small set of values is valid as input, maybe those can be expressed as an enumeration with a specific set of values rather than using a plain integer value to encode each possible value? Even if under the hood the enum collapses to an int, using enumerations protects from programmer mistakes.

If you cannot write the method signature in such a way that the exception condition cannot possibly happen in a well-formed program, then I would argue that this is exactly what ArgumentOutOfRangeException, IllegalArgumentException and similar exception types are intended for. This can also trivially be worked into a TDD workflow. Just make sure to make it clear what the error is; particularly if you don't have easy access to the source code, getting a non-specific ArgumentOutOfRangeException thrown back at you can be greatly frustrating. Note the documentation for these exception types:

ArgumentOutOfRangeException (.NET): "The exception that is thrown when the value of an argument is outside the allowable range of values as defined by the invoked method." (as seen here)

IllegalArgumentException (Java): "Thrown to indicate that a method has been passed an illegal or inappropriate argument." (as seen here)

Writing the method to make the exception condition impossible to begin with will help even more than throwing an exception at runtime, but we must acknowledge that sometimes this is just not possible in practice. You'll still need to check invariants not directly related to the range of a single parameter value at runtime, though; for example, if x + y > 20 is an error, but x and y each can be anything <= 20, I don't think there's an easy way to express that in the method signature.

share|improve this answer
    
@Katana314 Ceylon, for example. –  Darkhogg May 13 at 14:46
    
@Katana314 you mean haskell? –  Simon May 13 at 16:06
1  
I agree pushing the problem into types would be an even better solution. I imagine a language with advanced types that can check their values are within a certain range, or even fulfil certain conditions on assignment (e.g. prime, even, f(x)). Although there is an overhead to checking that would be redundant if the code would never produce invalid values anyway. –  joeytwiddle May 13 at 16:06
    
@joeytwiddle If we are talking about "advanced" types already, isn't that exactly the kind of work mutator functions are supposed to perform? –  Michael Kjörling May 13 at 17:05

I understand your question as "Should you validate input data?", as opposed to "Should you use Exceptions instead of error codes?".

When accepting input parameters from outside - be it a method with call-parameters, XML input data from a service call or a web-page with user-fields - you basically have two choices:

  1. make rigorus checks whether the input data match the expected format
  2. trust your caller to only call you with correct data

Adding checks adds complexity

  1. the initial developer has to think of all valid (or "possibly invalid") values and add appropriate checks. Ideally this is done at the beginning of the method, though sometimes it has to be done later (e.g. if "valid input value" is "the ID of an actually existing object in the database")
  2. further developers trying to understand the actual logic of the method, as it adds more lines to investigate.
  3. runtime overhead to check all assumptions

On the other hand, input validation brings valuable benefits:

  1. It enables you to make assumptions deeper down in the coding, as they are already verified
  2. further developers may have more to read, but making assumptions about input data explicit also helps understanding the logic, and that corner cases are taken care of.
  3. It ensures that no corrupt program states (crashes, data corruption, security vulnerabilities) can occur.

So the choice of adding checks should be done in context where your method is used.

  • Is it exposed to untrusted, external data, like web sites or public APIs? Then definitely do thorough validation.
  • is it a private method in an often-called inner-loop, protected by outer coding? Then you probably don't want redundant checks. You might want to document your expectations (e.g. JavaDoc), though that's rarely done in practice.
  • some languages provide conditionally compiled assertions, which are enabled in debug builds for catching program logic errors, but disabled for performance in productive use
  • for libraries you have to decide how much you trust your callers. Better err on the side of caution and add checks, especially if you don't want your library invariants to be compromised. For speed relevant functions, though, you could decide differently (and document it).
  • usually a mixture is done: good validation on externally facing methods, some validation on interface levels, very few (often just NullPointerChecks) in the inner workings of a program.

If your question however was "Are Exceptions the right way to signal invalid input data?", the answer is: most likely yes.

Exceptions impose quite an overhead on the runtime performance, but makes reasoning about the program flow drastically easier. This reduces faulty programming (semantic errors), especially as it forces you to deal with them - they 'fail securely' by terminating the program if they are ignored. They are ideal for 'situations which are not supposed to happen'. Also they can transport metadata like a stacktrace.

Error codes, on the other hand, are light-weight, fast, but forces the method caller to explicitely check them. Failure to do so often results in program flaws, which can range from silent data corruption, security holes, to nice fireworks if your program happens to be running inside a space rocket.

One example where I personally would have preferred error codes instead of exceptions is the String.parseInt() method in Java. Getting a non-digit string from an input source (e.g. a user) is not totally unexpected and I have to deal with it in any case - sometimes as simple as using a default value. As a caller, I have no way of checking the data whether it would provoce an exception (short of implementing the validator logic myself), thus generating the exception as part of normal program flow and using try-catch-blocks is the only choice here.

Please note that error codes could be both in-band and out-of-band:

  • In-band: a special (magic) value is declared to be a marker for the error condition. Often null or -1 is used here, e.g. in string-search-methods
  • Out-of-Band: a separate value is returned, indicating 'no error' (usually 0 or null) or the specific error. This can be done either as the / an additional return parameter (for languages supporting multiple return values - e.g. Googles GO supports this especially for errors) or as a requirement to call a special "getError()" method.
share|improve this answer

If I call a function, I expect it to do something. If it cannot do what I requested, I should be notified -- the function shouldn't do nothing or do something wrong.

I can be notified by it returning a specific return value (e.g. a floating point sqrt function could return NaN for a bad number), setting an external error variable, or throwing an exception. (The first or third are preferred.)

In your case, your function can't do what is requested of it when x is less than zero. Throwing an exception saying the argument is out of range is perfectly acceptable and nicely informative.

share|improve this answer
    
I'd add that it'd be nice to give the parameter name as part of the exception, even in the case of a method that takes a single parameter. –  jmoreno May 13 at 18:41
    
@jmoreno Yeah, that would definitely be an advantage of an exception or possibly even an error variable (w/ msg string) over a return value (unless you were using something like Haskell's Either type) –  paul May 13 at 19:01

I'd like to add another reason why throwing an exception is the best choice here: Unit-testing and TDD.

Every mature testing framework should be capable of asserting that a certain method throws when giving a certain input. By writing a unit test that checks for such an exception, you can document valid and invalid input for the method while at the same time validating that invalid input will indeed get rejected.

This is much harder when you're using assertions instead (or some other mechanism).

share|improve this answer
4  
I agree that an exception is the appropriate response here, but you fail to explain why. Assertions are for testing internal invariants that by design should never occur. They shouldn't be used to reject bad input to a public function because bad input is allowed by design. So while it's true that using an assertion in this case makes testing harder, it misses the point - assertions are being used the wrong way. Proper use of assertions wouldn't interfere with testing because code that fails an assertion is bugged and should fail its tests - the assertion ensures it and helps you debug. –  Doval May 13 at 12:21
    
@Doval, yes one should assert that an exception is actually thrown, many testing frameworks support catching and verifying exceptions –  Sebastian Godelet May 13 at 13:40
    
Add an exception so you can test to make sure the exception is thrown, is what you're saying here. –  emodendroket May 13 at 14:15

You should do something, as this answer says, exceptions are helpful, it's good to fail-fast etc etc. In fact I would add that they help at read time, I would say they document the intended input better than the top comment in your example.

However there are alternatives. If I've surmised your languages correctly: Debug.Assert(x > 0) and Contract.Requires( x > 0 );

However, the consensus seems to be that using exceptions in a release build is the best approach.

Asserts seem to be intended for debugging and it's more useful to ship with exceptions and that Contracts aren't quite there yet and neither is good for public methods. It's non-trivial, and doesn't lend itself to quick summary. I suggest reading that page.

Overall, I would tend to favour exceptions, but asserts may be a decent choice as well for internal methods.

share|improve this answer
2  
Assertions are often automatically disabled when not debugging (Debug.Assert will only be called when the debug flag is set), so it's more than just semantics / consensus. –  nmclean May 13 at 12:43
    
Good point. As you're link states, Trace.Assert is the one you would need for a release build, if you have enabled it. –  Nathan Cooper May 13 at 12:53

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