Rationale for Validation over exceptions?

Hi! I’ve been working with Gatling for a few months, and I’m finding that dealing with Validation values is a major pain point, especially since most people reading my code will be coming from Java and won’t understand the code if I start using flatMap all over the place. (I’ve taught Haskell; monads are a tough sell even with as much language support as you could want.)

I’d just like to know, why does Gatling use the Validation type, anyway? If it’s a performance matter, I’d be very interested in any benchmarks showing an improvement. If there’s a blog post or something, it’s not easily Googled. I’d like to link to something from a comment saying “this is why we put up with these Validation things,” but also I’ve been mulling it over, and it’s hard to think of why performance would improve, so if I’m wrong I’ve certainly got something to learn.

  • Luke

We use Validation internally so we can report the proper error messages, such as the name of the missing key when trying to fetch a value from the Session. It also made internal code way more maintainable.

Then, we don’t enforce Validation on end users: they can use as[T] if they want to code imperative style. And for comprehension can also help.

I’m not sure I follow. Couldn’t you use a custom Exception that remembers the key?

At any rate, the end user does end up having to deal with Validation in subtler ways. For instance, I seem to consistently need to use transformOption rather than transform because transformOption lets me return a Validation. Also, the internal API I’m building uses Expressions wherever possible, so I’m often needing to call them manually and hence extract from a Validation. This can be mitigated using utility functions, of course, but the impedance mismatch shows up everywhere.

Also, if it’s not intended that the user feel obligated to use Validation, I would suggest mentioning the alternatives in the page on Validation. Another thing that might help is if Failure.get() threw a special exception that could be caught by another utility method, something like:

def catchFailure[T](body : => T) : Validation[T] = { try { Success(body) } catch { case e : FailureException => Failure(e.message) } }

That would make it smoother to go from Validation to exception handling and back.

  • Luke