This explains how encoding invariants in Rust types - “parsing” input into refined types - avoids repeated runtime validation and clarifies client code. It starts with the annoyance that Vec::first returns Option even when higher-level logic already ensured a vector is non-empty. The remedy is to change the function’s return type from Vec to a dedicated NonEmpty<T> (head plus tail) so construction establishes the invariant once (NonEmpty::from_vec returns Option<NonEmpty<T>>), and callers can use first() without handling None. Concrete snippets show how get_configuration_directories becomes simpler and safer when it returns NonEmpty<PathBuf> instead of Vec<PathBuf>.
Multiple real-world Rust examples illustrate the pattern: a coreutils rewrite uses NonEmpty for pipeline commands, rust-analyzer implements a layered refinement PathBuf -> camino::Utf8PathBuf -> AbsPathBuf so UTF‑8 and absoluteness are proven at construction, and std::num::NonZeroUsize models nonzero counts (available_parallelism returns NonZeroUsize, enabling no-zero checks and Option size optimizations). Serde deserialization similarly “parses” JSON directly into typed structures (enums, NonZeroUsize), moving validation into parsing. The practical payoff is stronger, compiler-checked guarantees, clearer call sites, fewer runtime checks, and occasional storage or panic-safety benefits, compared with ad hoc validation common in dynamic languages.
Summary generated by AI from the linked article. hn.today is not affiliated with Hacker News or Y Combinator.