logoalt Hacker News

Parse, Don't Validate and Type-Driven Design in Rust

60 pointsby todsacerdotitoday at 7:40 PM24 commentsview on HN

Comments

dangtoday at 8:19 PM

Recent and related: Parse, Don't Validate (2019) - https://news.ycombinator.com/item?id=46960392 - Feb 2026 (172 comments)

also:

Parse, Don’t Validate – Some C Safety Tips - https://news.ycombinator.com/item?id=44507405 - July 2025 (73 comments)

Parse, Don't Validate (2019) - https://news.ycombinator.com/item?id=41031585 - July 2024 (102 comments)

Parse, don't validate (2019) - https://news.ycombinator.com/item?id=35053118 - March 2023 (219 comments)

Parse, Don't Validate (2019) - https://news.ycombinator.com/item?id=27639890 - June 2021 (270 comments)

Parsix: Parse Don't Validate - https://news.ycombinator.com/item?id=27166162 - May 2021 (107 comments)

Parse, Don’t Validate - https://news.ycombinator.com/item?id=21476261 - Nov 2019 (230 comments)

Parse, Don't Validate - https://news.ycombinator.com/item?id=21471753 - Nov 2019 (4 comments)

(p.s. these links are just to satisfy extra-curious readers - no criticism is intended! I add this because people sometimes assume otherwise)

show 1 reply
strawhatguytoday at 8:45 PM

The alternative is one type, with many functions that can operate on that type.

Like how clojure basically uses maps everywhere and the whole standard library allows you to manipulate them in various ways.

The main problem with the many type approach is several same it worse similar types, all incompatible.

show 4 replies
hutaotoday at 9:30 PM

Note that the division-by-zero example used in this article is not the best example to demonstrate "Parse, Don't Validate," because it relies on encapsulation. The principle of "Parse, Don't Validate" is best embodied by functions that transform untrusted data into some data type which is correct by construction.

Alexis King, the author of the original "Parse, Don't Validate" article, also published a follow-up, "Names are not type safety" [0] clarifying that the "newtype" pattern (such as hiding a nonzero integer in a wrapper type) provide weaker guarantees than correctness by construction. Her original "Parse, Don't Validate" article also includes the following caveat:

> Use abstract datatypes to make validators “look like” parsers. Sometimes, making an illegal state truly unrepresentable is just plain impractical given the tools Haskell provides, such as ensuring an integer is in a particular range. In that case, use an abstract newtype with a smart constructor to “fake” a parser from a validator.

So, an abstract data type that protects its inner data is really a "validator" that tries to resemble a "parser" in cases where the type system itself cannot encode the invariant.

The article's second example, the non-empty vec, is a better example, because it encodes within the type system the invariant that one element must exist. The crux of Alexis King's article is that programs should be structured so that functions return data types designed to be correct by construction, akin to a parser transforming less-structured data into more-structured data.

[0] https://lexi-lambda.github.io/blog/2020/11/01/names-are-not-...

fphtoday at 9:32 PM

The article quickly mentions implementing addition:

```

impl Add for NonZeroF32 { ... }

impl Add<f32> for NonZeroF32 { ... }

impl Add<NonZeroF32> for f32 { ... }

```

What type would it return though?

show 1 reply
noitpmedertoday at 8:38 PM

This reminds me a bit of a recent publication by Stroustrup about using concepts... in C++ to validate integer conversions automatically where necessary.

https://www.stroustrup.com/Concept-based-GP.pdf

  {
     Number<unsigned int> ii = 0;
     Number<char> cc = '0';
     ii = 2; // OK
     ii = -2; // throws
     cc = i; // OK if i is within cc’s range
     cc = -17; // OK if char is signed; otherwise throws
     cc = 1234; // throws if a char is 8 bits
  }
jaggederesttoday at 8:24 PM

You can go even further with this in other languages, with things like dependent typing - which can assert (among other interesting properties) that, for example, something like

    get_elem_at_index(array, index)
cannot ever have index outside the bounds of the array, but checked statically at compilation time - and this is the key, without knowing a priori what the length of array is.

"In Idris, a length-indexed vector is Vect n a (length n is in the type), and a valid index into length n is Fin n ('a natural number strictly less than n')."

Similar tricks work with division that might result in inf/-inf, to prevent them from typechecking, and more subtle implications in e.g. higher order types and functions

show 1 reply
cmovqtoday at 8:31 PM

Dividing a float by zero is usually perfectly valid. It has predictable outputs, and for some algorithms like collision detection this property is used to remove branches.

show 1 reply
sam0x17today at 8:48 PM

btw the “quoth” crate makes it really really easy to implement scannerless parsing in rust for arbitrary syntax, use it on many of my projects

show 1 reply