// HACKER NEWS — CYBERSECURITY
Rusty thoughts on "Parse, don't validate"
Like many programmers, I find Alexis King's Parse, don't validate
article fascinating, because it gives a name to an idiom that seems familiar and
important - one I've observed and used in the past without naming it explicitly.
This post is a review of the "Parse, don't validate" pattern applied to the Rust
programming language (the original post uses Haskell). I was particularly
interested in finding educational examples of this pattern in the Rust standard
library and other well-known projects.
Without repeating the original article (please read it first!), here's the
gist of it.
Consider the venerable Vec; its first method returns Option<&T>.
Why? Because a vector is not guaranteed to have any elements in it, so what
to do if first is invoked on an empty one? Returning an Option in this
case is idiomatic in Rust [1], with convenient syntax sugar for accepting
the result of functions that return Option and deciding what to do next.
Imagine we have a function to read some configuration paths from an env var,
while enforcing the invariant that the list can't be empty:
So far, so good. Now let's take a typical usage of this function:
Once get_configuration_directories returns a successful result,
we are guaranteed that the vector isn't empty. And yet, if we want to get the
first element of this vector, we have to use the first method that returns
Option<&T>. We are therefore forced - again - to handle a potentially
empty case (where the option is None).
As the original article states, this has a number of problems with code clarity,
potential performance implications and a ticking time bomb if the invariant
is ever changed in get_configuration_directories.
The core issue is that Vec is fundamentally a type that can be empty; we
can carry along a "This one can't be empty, pinky promise!" comment on all the
relevant code, but it's not formally checked by anything.
The solution is leveraging the type system to enforce a newly established
invariant. We can use a separate type for "a vector that cannot be empty";
in fact, such types already exist in several Rust crates - for example
nonempty:
This type has no constructor that permits "no elements"; its new takes
one element, and its first method returns &T without an Option: