Live data from Hacker News

Parse, Don't Validate (2019)

lexi-lambda.github.io

81–90 of 175 posts

Re: Parse, Don't Validate (2019)

#81

The author's point here is great, but the post does (imho) a poor job illustrating it. The tl;dr on this is: stop sprinkling guards and if statements all over your codebase. Convert (parse) the data into truthful objects/structs/containers at the perimieter. The goal is to do that work at the boundaries of your system, so that inside of your system you can stop worrying about it and trust the value objects you have.…

I understand where you're coming from, but these terms seem fine to me:

This is exactly what, for example, Rust's str::parse method is for. The documentation gives the example:

    let four: u32 = "4".parse().unwrap();
You will so very often have text and want typed information, and parse is exactly how we do that transformation exactly once. Whereas validation is what it looks like when we try to make piecemeal checks later.

Re: Parse, Don't Validate (2019)

#82

Earlier quoted context omitted.

> it feels like sometime after Java got popular [...] a large chunk of the collective programming community forgot why strong static type checking was invented and are now having to rediscover this. I think you have a very rose-tinted view of the past: while on the academic side static types were intended for proof on the industrial side it was for efficiency. C didn't get static types in order to prove your code was…

> I think you have a very rose-tinted view of the past I think they also forgot the entire Perl era.

That's understandable. Youthful indiscretion is best forgotten.

Re: Parse, Don't Validate (2019)

#83
post #12
post #8

Earlier quoted context omitted.

record PhoneNumber(String value) {} Huge pain.

What have you gained?

Validation, readability, and prevention of accidentally passing in the wrong string (e.g., by misordering two strings arguments in a function).

Re: Parse, Don't Validate (2019)

#84

It seems modern statically-typed and even dynamically-typed languages all adopted this idea, except Go, where they decided zero values represent valid states always (or mostly). A sincere question to Go programmers – what's your take on "Parse, Don't Validate"?

> what's your take on "Parse, Don't Validate"

Always aspire to that. Translating that to Go conventions, the constructor has to have signature like:

    func NewT() (T, error) {
      ...
    }
Such signatures exist in the stdlib, e.g. https://cs.opensource.google/go/go/+/refs/tags/go1.25.7:src/... although I've met old-hands that were surprised by it.

In larger codebases, I've noticed an emergent phenomenon that usually the T{} itself (bypassing NewT constructor) tends to be unusable anyway, hence the constructor will enforce "parse, don't validate" just well enough. Only very trivial T{} won't have a nilable private field, such as a pointer, func, or chan.

I'd say that "making zero a meaningful value" does not scale well when codebase grows.

Re: Parse, Don't Validate (2019)

#85
post #75
post #7

Earlier quoted context omitted.

> In most strong statically typed languages, you wouldn't often pass strings and generic dictionaries around. In 99% of the projects I worked on my professional life, anything that is coming from an human input is manipulated as a string and most of the time, it stays like this in all of the application layers (with more or less checks in the path). On your precise exemple, I can even say that I never saw something l…

Trying to parse email will result in bad assumptions. Better be a plain string than a bad regex. For examples many website reject + character, which is totally valid and gmail uses that for temporary emails. Same for adresses.

Recently got a bank account which allowed my custom domain during registration, but rejected it as invalid during login. The problem? Their JS client code has a bad regex rejecting TLDs longer than 4 chars (trivial for a dev to bypass, but wow.)

Re: Parse, Don't Validate (2019)

#86
post #7

Earlier quoted context omitted.

> In most strong statically typed languages, you wouldn't often pass strings and generic dictionaries around. In 99% of the projects I worked on my professional life, anything that is coming from an human input is manipulated as a string and most of the time, it stays like this in all of the application layers (with more or less checks in the path). On your precise exemple, I can even say that I never saw something l…

this is likely an ecosystem sort of thing. if your language gives you the tools to do so at no cost (memory/performance) then folks will naturally utilize those features and it will eventually become idiomatic code. kotlin value classes are exactly this and they are everywhere: https://kotlinlang.org/docs/inline-classes.html

Haxe has a really elegant solution to this in the form of Abstracts[0][1]. I wonder why this particular feature never became popular in other languages, at least to my knowledge.

0 - https://code.haxe.org/category/abstract-types/color.html

1 - https://haxe.org/manual/types-abstract.html

Re: Parse, Don't Validate (2019)

#87
post #66

Earlier quoted context omitted.

I disagree. I think the key insight is to carry the proof with you in the structure of the type you 'parse' into.

Could you clarify what you mean by "carry the proof"?

From the article:

    validateNonEmpty :: [a] -> IO ()
    validateNonEmpty (_:_) = pure ()
    validateNonEmpty [] = throwIO $ userError "list cannot be empty"
    
    parseNonEmpty :: [a] -> IO (NonEmpty a)
    parseNonEmpty (x:xs) = pure (x:|xs)
    parseNonEmpty [] = throwIO $ userError "list cannot be empty"
Both consolidate all the invariants about your data; in this example there is only one invariant but I think you can get the point. The key difference between the "validate" and "parse" versions is that the structure of `NonEmpty` carries the proof that the list is not empty. Unlike the ordinary linked list, by definition you cannot have a nil value in a `NonEmpty` and you can know this statically anywhere further down the call stack.

Re: Parse, Don't Validate (2019)

#88
post #66

Earlier quoted context omitted.

I disagree. I think the key insight is to carry the proof with you in the structure of the type you 'parse' into.

Could you clarify what you mean by "carry the proof"?

Let's say you have the example from the article of wanting a non-empty list, but you don't use the NonEmpty type and instead are just using an ordinary list. As functions get called that require the NonEmpty property, they either have to trust that the data was validated earlier or perform the validation themselves. The data and its type carry no proof that it is, in fact, non-empty.

If you instead parse the data (which includes a validation step) and produce a Maybe NonEmpty, if the result is a Just NonEmpty (vs Nothing) you can pass around the NonEmpty result to all the calls and no more validation ever needs to occur in the code from that point on, and you obviously reject it rather than continue if the result is Nothing. Once you have a NonEmpty result, you have a proof (the type itself) that is carried with it in the rest of the program.

Re: Parse, Don't Validate (2019)

#89
> Now I have a single, snappy slogan that encapsulates what type-driven design means to me, and better yet, it’s only three words long

IMHO this is distracting and sort of vain. It forces this "semantics" perspective into the reader, just so the author can have a snappy slogan.

Also, not all languages have such freedom in type expressiveness. Some of them have but offer terrible trade-ofs.

The truth is, if you try to be that expressive in a language that doesn't support it you'll end up with a horror story. The article fails to mention that, and that "snappy slogan" makes it look like it's an absolute claim that you must internalize, some sort of deep truth that applies everywhere. It isn't.

Re: Parse, Don't Validate (2019)

#90
I'm sorry, I don't like to title drop, but I am a Staff Data Engineer and I find that "type driven" development is an inappropriate world view for many programming contexts that I encounter. I use "world view" carefully as it makes a contractual assumption about reality -- "give me what I expect". Data processing does not always have the luxury of such imposition. In these contexts a dynamic and introspective world view is more appropriate, "What do we have here?" "What can we use?". In 2019 I would have felt crippled by use of Haskell in data processing contexts and have instead done much in Clojure in these intervening years, though now LLM assisted use of Haskell toward such tasks would be a fun spectator sport.
Post reply on HN