Live data from Hacker News

Parse, Don't Validate (2019)

lexi-lambda.github.io

31–40 of 288 posts

Re: Parse, Don't Validate (2019)

#31

This still sounds like validation but with extra steps. (or less?)

The post is saying:

- don't drop the info gathered from checks while validating, but keep track of it

- if you do this, you'll effectively be parsing

- parsing is more powerful that validating

"Extra steps" would be keeping track of info gathered from checks.

Re: Parse, Don't Validate (2019)

#32

When I think of validation I think of receiving a data file and checking that all rows and columns are correct and generating a report about all the problems. Does my thing have a different name? Where can I read up on how to do that best?

I thought of input validation for web forms. Similar thing I guess. In Haskell you can create a type that you know is a validated email address but you still need a validation function from String -> Maybe Email to actually validate it at runtime

Re: Parse, Don't Validate (2019)

#34

In typescript parsing/asserting types with combinators works very well merging runtime with static type system [0], it has to be used at i/o boundary, then it enters static type system guarantee and no assertions are necessary, makes very nice codebase. [0] https://github.com/appliedblockchain/assert-combinators

I wish it had actual proper examples. I've no idea how to use that.

from a look at the readme, you combine those `$.TYPE` things to build a validation function that checks if its argument matches some pattern (and throws an exception if it doesn't).

  import * as $ from '@appliedblockchain/assert-combinators'

  const validateFooBar = (
    $.object({
      foo: $.string,
      bar: $.boolean
    })
  )
  // probably roughly equivalent to
  /*
  const validateFooBar = (x) => {
    console.assert(
      typeof x === 'object' &&
      typeof x.foo === 'string' &&
      typeof x.bar === 'boolean'
    )
    return x
  }
  */


  const test1 = { foo: "abc", bar: false }
  const test2 = { foo: 0, quux: true } 
  const { foo, bar } = validateFooBar(test1) // ok
  const oops = validateFooBar(test2) // throws error
the source is pretty readable too if you want to get an idea how it works.

https://github.com/appliedblockchain/assert-combinators/blob...

https://github.com/appliedblockchain/assert-combinators/blob...

Re: Parse, Don't Validate (2019)

#35
post #19
post #2

Software Engineers: Parse, don't validate. Mathematicians: Parsing is validation https://gallais.github.io/pdf/draft_sigbovik21.pdf

To everyone in this subthread: sigbovik is a conference published every 1st of April. This paper is an April's fool joke. I didn't think people could take that one seriously. I guess it's a good April's fool then. :)

The conference is indeed a spoof, but in so far as what Mathematicians call a "proof" - the paper contains one. Agda is a proof assistant in the spirit of the Calculus of Constructions ( https://en.wikipedia.org/wiki/Calculus_of_constructions ).

So is the joke on Computer Scientists or Mathematicians? You decide ;)

Beware of bugs in the above code; I have only proved it correct, not tried it --Donald Knuth

Re: Parse, Don't Validate (2019)

#37

When I think of validation I think of receiving a data file and checking that all rows and columns are correct and generating a report about all the problems. Does my thing have a different name? Where can I read up on how to do that best?

Data validation?

Re: Parse, Don't Validate (2019)

#38
This is a great post. I come back to it frequently.

There's beautiful clarity in the articulation, and the essence is easy to grasp yet powerful. It reminds me a bit of Scott Wlaschin's Railway Oriented Programming (ROP) [0]. As a technique, ROP nicely complements "parse don't validate". As an explanation, it's similarly simple yet wonderfully effective.

I've a real admiration for people who can explain and present things so clearly. With ROP, for example, the reader learns the basics of monads without even realising it.

[0]: https://fsharpforfunandprofit.com/rop/

Re: Parse, Don't Validate (2019)

#40
post #10

Earlier quoted context omitted.

The word “is” is also often used informally to mean “is a kind of”.

"A kind of" is precisely its formal use from the PoV of a type theorist. Two things are the same type of thing if they share all of their extensional properties. That is what it means for two things to be identical/equal.

But what I am saying is that parsing is a kind of validation. But all validation is not parsing.

For example let's say that I have written an HTTP API that accepts application/x-www-form-urlencoded data to one of its endpoints. Let's say `POST /users`, and this is where the client-side application posts data to.

Now I can implement this in many ways. I can for example define

    pub struct Person {
        name: String,
        phone_number: String,
    }
But how I populate this struct can determine whether I am actually parsing or not, even if most of the code aside from that is the same.

And of course I could go further and define types for the name and the phone number but in this case lets say that I have decided that strings are the proper representation in this case.

If the fields of my structs were directly accessible

    pub struct Person {
        pub name: String,
        pub phone_number: String,
    }
And in my HTTP API endpoint for `POST /users` I do the following:

    // ...
    
    let name = post_data.name;
    let phone_number = post_data.phone_number;

    let norwegian_phone_number_format = Regex::new(r"^(\+47|0047)?\d{8}$").unwrap();

    // ...
And I didn't bother to write out the rest of the code here for this example but you get the gist.

The point is that here I am doing some rudimentary validation on the phone number, requiring it to be in Norwegian format. But I am enforcing this in the implementation of the handler for the HTTP API endpoint, rather than in the data type itself.

Whereas if I was instead doing

    pub struct Person {
        name: String,
        phone_number: String,
    }

    impl Person {
        pub fn try_new (name: String, phone_number: String) -> std::result::Result {
            // ...

            let norwegian_phone_number_format = Regex::new(r"^(\+47|0047)?\d{8}$").unwrap();

            // ...
        }
    }
Now I've moved the validation into an associated function of the type itself, and I've made the fields of the struct unaccessible from the outside.

And in this manner, even though my validation is still rudimentary, and a type purist might find the type insufficiently constrained, I have indeed in my own book gone from just validation to actual parsing. Because I have made it so that the construction of the type enforces the constraints on the data.

Post reply on HN