Coding Range

Thoughts on Using Exceptions

February 2nd, 2015

When I started this blog, and then neglected it and revived it several times, I never thought I’d use the advice-column format. When a friend of mine asked me for some advice though, I thought I should share it with anyone else who might have the same question.

They definitely didn’t teach this type of writing in high-school English classes.

Anyway, an anonymous friend asks:

Earlier at work during a code review meeting we were chatting about validation, what we should do and what we should avoid doing. I wrote a bit of code that automatically gets executed when my web application wants to ensure that a String looks like a valid date. This code essentially calls a standard Java API method to parse the String as a date, and if a parsing exception is thrown by this API method, then I catch the exception and say that the validation failed. My colleagues told me that this is not how I should have done it, for several reasons:

  • Generally speaking, throwing exceptions isn’t good, performance wise, as you’re building an object with references to your whole stack.
  • Exceptions should be for… exceptional cases, not expected cases.
  • Exceptions shouldn’t be used for validation. They’re meant to say that something fucked up.

They advised me to determine whether a date looks valid using a regex and only then send it to the parsing API method. All these explanations make sense to me, but I’d like to get the opinion of someone completely unrelated to the company.

I don’t know how much you know Java, but since a lot of languages support exceptions, my question is pretty much language-agnostic. So what do you think of that?

In my opinion, your coworkers are right. But also wrong.

I generally deal with C# at work so what I say below will likely reflect that, but it should apply to most programming environments.

Your colleagues said that throwing exceptions isn’t good from a performance point of view. This has been my experience as well. In one place at work, for example, the only way to return a HTTP 304 from a particular web application, due to the framework we use, is to throw an exception. Often, a 304 response, which means “hey, your cached value is good to use”, is slower than actually retrieving the full resource. We check this by last modified date, so we don’t need to load the value itself to revalidate the cache. This means that checking the date, throwing the exception and unwinding the stack is sometimes slower than checking the date, connecting to a database server and returning the actual value.

Conversely - I haven’t tested this one myself but try { new Guid(..) } catch is allegedly faster than try { Guid.Parse } catch or Guid.TryParse. When making performance decisions, these need to be checked on a case-by-case basis, using a profiling tool. Don’t assume.

Your colleagues also said that exceptions should be used for exceptional cases, not expected cases. This is something I try to hold to, though frameworks sometimes don’t allow for it (as above). Sometimes you have to use a try..catch or throw an exception with no other alternative. Sometimes, though, you have a choice, and I usually try follow the choices without exceptions.

Objective-C takes an interesting approach to exceptions. Objective-C uses NSError objects (as output parameters) and a nil or NO (FALSE) return value to indicate an expected failure. NSException is reserved for when it’s clear that the programmer screwed something up.

Java - as far as I know - makes exceptions part of the method contract, and the compiler enforces that you catch every expected exceptions (or rethrow it as an unchecked exception type). In my experience, however, Java does use exceptions for many expected failures. So does C#. That doesn’t mean that we can’t do better in application code, but it does make it harder.

Lastly, your colleagues said that exceptions shouldn’t be used for validation. I agree with this, since the whole point of validation is to take untrusted input and validate it. Failure is expected, that’s the entire point of validation. However, this is not mutually exclusive with catching an exception from Java’s Date API. For example (based on what I found from Google quickly):

DateValidationResult validateDateInput(string inputValue)
{
    try
    {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
        LocalDate date = LocalDate.parse(inputValue, formatter);
        return DateValidationResult.fromLocalDate(date);
    }
    catch (DateTimeParseException ex)
    {
        return DateValidationResult.failure;
    }
}

This uses an exception for validation, but doesn’t expose it. On the other hand, I disagree with the below example:

LocalDate validateDateInput(string inputValue) throws ValidationException
{
    try
    {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");
        LocalDate date = LocalDate.parse(inputValue, formatter);
        return date;
    }
    catch (DateTimeParseException ex)
    {
        throw new ValidationException(ex);
    }
}

This example uses an exception for validation, but uses the exception to indicate success or failure, and ultimately, control program flow.

So on those three points, I pretty much agree with your colleagues. However, I don’t agree with their recommendation to pre-validate.

When you pre-validate with a regular expression or other means, your failure flow looks like this:

  1. Check if the value is valid.
  2. The value is invalid. Return a failure.

Your success flow though, looks like this.

  1. Check if the value is valid.
  2. The value is valid. Pass it to a system function.
  3. Parse and check if the value is valid.
  4. The value is valid. Return the new value type.
  5. Return the new value type from the system function.

Thus, when adding pre-validation, you end up validating the value twice on the success case.

For this, I recommend using a function that returns a value on success, and an error value on failure. This way:

  • You avoid exceptions
  • You only examine the input once

In C#-land, most types have a TryParse function with this signature:

bool TryParse(string value, out TypeName outValue)

This returns true on success and returns the parsed value via the out parameter, and returns false on failure. This can then be used as follows:

string untrustedInput = "...";
DateTime dateTime;
if (!DateTime.TryParse(untrustedInput, out dateTime))
{
    // Handle the failure
}

// Continue success operation

It looks like Java has a similar API. SimpleDateFormat.parse(String, ParsePosition) is documented to return a Date object on success and null on failure, so that should give you the best of both worlds.

So, to summarise:

  1. Don’t make assumptions about performance. Check them.
  2. Avoid using exceptions for expected code paths. Reserve them for when something has gone really wrong, or when you have no choice.
  3. Make sure your code doesn’t unnecceasrily double up on itself. It might not look like repeated code, but it can still be.