Y
HN HRCB new | past | comments | ask | show | by right | domains | dashboard | about hrcb
+0.17 Parse, Don't Validate and Type-Driven Design in Rust (www.harudagondi.space)
249 points by todsacerdoti 3 days ago | 72 comments on HN | Mild positive Editorial · vv3.4 · 2026-02-24
Article Heatmap
Preamble: ND — Preamble Preamble: No Data — Preamble P Article 1: ND — Freedom, Equality, Brotherhood Article 1: No Data — Freedom, Equality, Brotherhood 1 Article 2: +0.07 — Non-Discrimination 2 Article 3: ND — Life, Liberty, Security Article 3: No Data — Life, Liberty, Security 3 Article 4: ND — No Slavery Article 4: No Data — No Slavery 4 Article 5: ND — No Torture Article 5: No Data — No Torture 5 Article 6: ND — Legal Personhood Article 6: No Data — Legal Personhood 6 Article 7: ND — Equality Before Law Article 7: No Data — Equality Before Law 7 Article 8: ND — Right to Remedy Article 8: No Data — Right to Remedy 8 Article 9: ND — No Arbitrary Detention Article 9: No Data — No Arbitrary Detention 9 Article 10: ND — Fair Hearing Article 10: No Data — Fair Hearing 10 Article 11: ND — Presumption of Innocence Article 11: No Data — Presumption of Innocence 11 Article 12: ND — Privacy Article 12: No Data — Privacy 12 Article 13: ND — Freedom of Movement Article 13: No Data — Freedom of Movement 13 Article 14: ND — Asylum Article 14: No Data — Asylum 14 Article 15: ND — Nationality Article 15: No Data — Nationality 15 Article 16: ND — Marriage & Family Article 16: No Data — Marriage & Family 16 Article 17: ND — Property Article 17: No Data — Property 17 Article 18: ND — Freedom of Thought Article 18: No Data — Freedom of Thought 18 Article 19: +0.22 — Freedom of Expression 19 Article 20: ND — Assembly & Association Article 20: No Data — Assembly & Association 20 Article 21: ND — Political Participation Article 21: No Data — Political Participation 21 Article 22: ND — Social Security Article 22: No Data — Social Security 22 Article 23: ND — Work & Equal Pay Article 23: No Data — Work & Equal Pay 23 Article 24: ND — Rest & Leisure Article 24: No Data — Rest & Leisure 24 Article 25: ND — Standard of Living Article 25: No Data — Standard of Living 25 Article 26: +0.19 — Education 26 Article 27: ND — Cultural Participation Article 27: No Data — Cultural Participation 27 Article 28: ND — Social & International Order Article 28: No Data — Social & International Order 28 Article 29: ND — Duties to Community Article 29: No Data — Duties to Community 29 Article 30: ND — No Destruction of Rights Article 30: No Data — No Destruction of Rights 30
Negative Neutral Positive No Data
Aggregates
Weighted Mean +0.17 Unweighted Mean +0.16
Max +0.22 Article 19 Min +0.07 Article 2
Signal 3 No Data 28
Confidence 5% Volatility 0.07 (Low)
Negative 0 Channels E: 0.6 S: 0.4
SETL +0.06 Editorial-dominant
Evidence: High: 0 Medium: 2 Low: 1 No Data: 28
Theme Radar
Foundation Security Legal Privacy & Movement Personal Expression Economic & Social Cultural Order & Duties Foundation: 0.07 (1 articles) Security: 0.00 (0 articles) Legal: 0.00 (0 articles) Privacy & Movement: 0.00 (0 articles) Personal: 0.00 (0 articles) Expression: 0.22 (1 articles) Economic & Social: 0.00 (0 articles) Cultural: 0.19 (1 articles) Order & Duties: 0.00 (0 articles)
Domain Context Profile
Element Modifier Affects Note
Privacy
No privacy policy or statement observable on-domain from provided content.
Terms of Service
No terms of service observable on-domain from provided content.
Accessibility +0.05
Article 2 Article 19
Site uses semantic HTML structure, heading hierarchy (h1-h6), and responsive design. Dark mode support observable. Minor positive for accessibility affordances.
Mission
No explicit mission or values statement observable on-domain.
Editorial Code
No editorial code of conduct or ethics statement observable on-domain.
Ownership
Personal blog by @harudagondi; no corporate entity or ownership restrictions observable.
Access Model +0.08
Article 19 Article 26
Content appears freely accessible; no paywall or access restrictions observable. Supports open information access.
Ad/Tracking
No advertising or tracking signals observable in provided content.
HN Discussion 14 top-level comments
dang 2026-02-21 20:19 UTC link
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)

jaggederest 2026-02-21 20:24 UTC link
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

cmovq 2026-02-21 20:31 UTC link
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.
noitpmeder 2026-02-21 20:38 UTC link
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
  }
strawhatguy 2026-02-21 20:45 UTC link
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.

sam0x17 2026-02-21 20:48 UTC link
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
hutao 2026-02-21 21:30 UTC link
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-...

fph 2026-02-21 21:32 UTC link
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?

the__alchemist 2026-02-21 22:33 UTC link
The examples in question propagate complexity throughout related code. I think this is a case I see frequently in Rust of using too many abstractions, and its associated complexities.

I would just (as a default; the situation varies)... validate prior to the division and handle as appropriate.

The analogous situation I encounter frequently is indexing, e.g. checking if the index is out of bounds. Similar idea; check; print or display an error, then fail that computation without crashing the program. Usually an indication of some bug, which can be tracked down. Or, if it's an array frequently indexed, use a (Canonical for Rust's core) `get` method on the whatever struct owns the array. It returns an Option.

I do think either the article's approach, or validating is better than runtime crashes! There are many patterns in programming. Using Types in this way is something I see a lot of in OSS rust, but it is not my cup of tea. Not heinous in this case, but I think not worth it.

This is the key to this article's philosophy, near the bottom:

> I love creating more types. Five million types for everyone please.

unixpickle 2026-02-21 23:44 UTC link
The `try_roots` example here is actually a _counterexample_ to the author's main argument. They explicitly ignore the "negative discriminant" case. What happens if we consider it?

If we take their "parse" approach, then the types of the arguments a, b, and c have to somehow encode the constraint `b^2 - 4ac >= 0`. This would be a total mess--I can't think of any clean way to do this in Rust. It makes _much_ more sense to simply return an Option and do the validation within the function.

In general, I think validation is often the best way to solve the problem. The only counterexample, which the author fixates on in the post, is when one particular value is constrained in a clean, statically verifiable way. Most of the time, validation is used to check (possibly complex) interactions between multiple values, and "parsing" isn't at all convenient.

AxiomLab 2026-02-22 07:52 UTC link
This exact philosophy is why I started treating UI design systems like compilers.

Instead of validating visual outputs after the fact (like linting CSS or manual design reviews), you parse the constraints upfront. If a layout component is strictly typed to only accept discrete grid multiples, an arbitrary 13px margin becomes a compile error, not a subjective design debate. It forces determinism.

barnacs 2026-02-22 13:29 UTC link
Every time you introduce a type for a "value invariant" you lose compatibility and force others to make cumbersome type conversions.

To me, invalid values are best expressed with optional error returns along with the value that are part of the function signature. Types are best used to only encode information about the hierarchy of structures composed of primitive types. They help define and navigate the representation of composite things as opposed to just having dynamic nested maps of arbitrary strings.

ubixar 2026-02-22 14:47 UTC link
C# gets close to this with records + pattern matching, F# discriminated unions are even better for this with algebraic data types built right in. A Result<'T,'Error> makes invalid states unrepresentable without any ceremony. C# records/matching works for now, but native DUs will make it even nicer.
cadamsdotcom 2026-02-22 20:46 UTC link
Parsing over validation, and newtypes for everything, fall over when you don’t know the full range of possibilities that can occur in the wild.

It is a handy way to prevent divide by zero as in the article, or to have fun with lambda calculus by asking the type system if 3 + 4 == 8. You can reason about the full range of inputs. Same for file format parsing - making as many failure modes as possible fail as early as possible!

But be VERY wary of using them to represent business logic or state machines that allow only the transitions you believe can exist at this point in time. You just don’t know what wild things people will want to do in business logic, and if your software can’t handle those scenarios, people will just work around it and your stuff no longer matches reality.

Score Breakdown
ND
Preamble Preamble

Content is technical software engineering instruction. No observable engagement with human rights principles, dignity, freedom, or justice concepts in preamble context.

ND
Article 1 Freedom, Equality, Brotherhood

No observable content addressing equal rights, dignity, or reason/conscience.

+0.07
Article 2 Non-Discrimination
Low Practice
Editorial
ND
Structural
+0.05
SETL
ND
Combined
ND
Context Modifier
ND

Accessibility features (semantic HTML, heading structure, responsive design, dark mode) provide structural affordances for non-discriminatory access to information. Low evidence strength as accessibility features are incidental to primary purpose.

ND
Article 3 Life, Liberty, Security

No observable content addressing security of person or physical integrity.

ND
Article 4 No Slavery

No observable content addressing slavery or servitude.

ND
Article 5 No Torture

No observable content addressing torture or cruel punishment.

ND
Article 6 Legal Personhood

No observable content addressing right to life or personhood.

ND
Article 7 Equality Before Law

No observable content addressing legal equality or discrimination.

ND
Article 8 Right to Remedy

No observable content addressing effective remedies or legal recourse.

ND
Article 9 No Arbitrary Detention

No observable content addressing arbitrary arrest or detention.

ND
Article 10 Fair Hearing

No observable content addressing fair trial or impartial hearing.

ND
Article 11 Presumption of Innocence

No observable content addressing criminal procedure or presumption of innocence.

ND
Article 12 Privacy

No observable content addressing privacy or family protection.

ND
Article 13 Freedom of Movement

No observable content addressing freedom of movement.

ND
Article 14 Asylum

No observable content addressing asylum or refugee protection.

ND
Article 15 Nationality

No observable content addressing nationality or citizenship.

ND
Article 16 Marriage & Family

No observable content addressing marriage or family rights.

ND
Article 17 Property

No observable content addressing property rights.

ND
Article 18 Freedom of Thought

No observable content addressing freedom of thought, conscience, or religion.

+0.22
Article 19 Freedom of Expression
Medium Advocacy Practice
Editorial
+0.15
Structural
+0.12
SETL
+0.07
Combined
ND
Context Modifier
ND

Article explicitly discusses sharing knowledge/information (technical education via blog post). Free access to content without paywall supports freedom of opinion and information. Author advocates for making Haskell concepts accessible to Rust community (inclusive information sharing). Structural: freely accessible, no registration barriers, open technical information dissemination.

ND
Article 20 Assembly & Association

No observable content addressing freedom of assembly or association.

ND
Article 21 Political Participation

No observable content addressing participation in government or public affairs.

ND
Article 22 Social Security

No observable content addressing social security or welfare.

ND
Article 23 Work & Equal Pay

No observable content addressing work or employment rights.

ND
Article 24 Rest & Leisure

No observable content addressing rest or leisure.

ND
Article 25 Standard of Living

No observable content addressing health, food, or housing.

+0.19
Article 26 Education
Medium Advocacy Practice
Editorial
+0.12
Structural
+0.10
SETL
+0.05
Combined
ND
Context Modifier
ND

Content provides technical education on programming language design principles. Author explicitly frames content as educational resource for Rust community (technical development of human capacity). Free access supports right to education. No observable discriminatory gatekeeping. Medium evidence: education content is secondary to technical focus.

ND
Article 27 Cultural Participation

No observable content addressing cultural participation or intellectual property ethics.

ND
Article 28 Social & International Order

No observable content addressing social and international order.

ND
Article 29 Duties to Community

No observable content addressing community duties or limitations on rights.

ND
Article 30 No Destruction of Rights

No observable content addressing prevention of rights destruction.

About HRCB | By Right | HN Guidelines | HN FAQ | Source | UDHR
build fc56cf0+0q5s · 2026-02-25 01:32 UTC