17

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?

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

6 Answers 6

20

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. :)

7
  • 4
    It's worth noting that not all languages allow specifying exceptions in method signatures.
    – DougM
    Commented May 13, 2014 at 12:53
  • 1
    @DougM I can think of only one that does: Java. And possibly Ada.
    – user
    Commented May 13, 2014 at 13:01
  • 8
    In which language is throwing an exception "the error at compile-time"? Commented May 13, 2014 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
    Commented May 13, 2014 at 15:09
  • 2
    @jozefg Oh definitely, which is why no sane person uses them in C++ - but still you can specify the exceptions in method signatures :-)
    – Voo
    Commented May 13, 2014 at 17:42
15

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.

4
  • @Katana314 Ceylon, for example.
    – Darkhogg
    Commented May 13, 2014 at 14:46
  • @Katana314 you mean haskell? Commented May 13, 2014 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. Commented May 13, 2014 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?
    – user
    Commented May 13, 2014 at 17:05
11

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.
5

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).

3
  • 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
    Commented May 13, 2014 at 12:21
  • 1
    @Doval, yes one should assert that an exception is actually thrown, many testing frameworks support catching and verifying exceptions Commented May 13, 2014 at 13:40
  • Add an exception so you can test to make sure the exception is thrown, is what you're saying here.
    – Casey
    Commented May 13, 2014 at 14:15
5

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.

2
  • 2
    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
    Commented May 13, 2014 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
    Commented May 13, 2014 at 19:01
4

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.

2
  • 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
    Commented May 13, 2014 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
    Commented May 13, 2014 at 12:53

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