Applying 'Parse, don't validate' pattern to Rust development
Using specialized types instead of simple validation allows the Rust type system to enforce data invariants at compile time.
Summary
An analysis by Eli Bendersky explores the 'Parse, don't validate' idiom within the context of the Rust programming language. The article demonstrates how replacing standard types like Vec with specialized types like NonEmpty can eliminate redundant runtime checks and prevent logic errors. Real-world examples from the Rust standard library, rust-analyzer, and the nonempty crate illustrate how type refinement improves code safety and clarity.
Type-driven invariant enforcement
- Validation vs. Parsing: Validation checks if data meets criteria but returns the same type; parsing transforms data into a new type that carries the proof of validity.
- NonEmpty Pattern: Using a struct like
NonEmpty<T>(containing ahead: Tandtail: Vec<T>) ensures the collection cannot be empty, allowingfirst()to return&Tinstead ofOption<&T>. - Type Refinement: Projects like rust-analyzer use wrapper types (e.g.,
AbsPathBuf) to encode properties like 'absolute path' into the type itself. - Memory Optimization: The
NonZero<T>type in Rust allowsOption<NonZero<T>>to occupy the same memory space asNonZero<T>by using the zero bit pattern to representNone.
Why it matters
This pattern encourages more robust software design in the Rust ecosystem by moving runtime error handling to compile-time type guarantees.
Original reference: eli.thegreenplace.net →