Live data from Hacker News

"Parse, don't validate" through the years with C++

derekrodriguez.dev

41–50 of 52 posts

Re: "Parse, don't validate" through the years with C++

#41
Heh, I can especially tell the first code example is LLM-generated. Humans don't usually write comments like:

   // There are a few ways to let API callers bring their own 
   // memory, as they would in a no-malloc environment and this
   // stack-friendly c'tor is a stand-in for that. 
There's just something about this comment that doesn't feel right. I've seen these kinds of phrasings in LLM output before but I'm not sure exactly how to describe them.

Re: "Parse, don't validate" through the years with C++

#42

Earlier quoted context omitted.

I hope this is not trolling so I'll bite. It is incredibly natural to represent an object, such as an email, as an Email class in object oriented languages like C++. It'd then have a constructor that accepts a string and constructs the email object from said string, or maybe a parse(string) -> Option thingy. The type system then ensures the checks are present whenever they have to be, and nowhere else. Tl;dr: there's…

I completely agree with you but I think sometimes folks carry some piece of data around as a string or int instead of something more concrete like a class or a strongly typed enum etc purely out of laziness!

I think the old Lisp tradition of using lists for everything is related to this somehow. On the other hand, in Common Lisp programmers can define custom types that have to fulfill a predicate function. Then, if they declare the types of their functions, most implementations will generate type-checking code unless instructed not to. So in Common Lisp you can use lists for everything but still have type-checking, at some cost to efficiency. :D

Re: "Parse, don't validate" through the years with C++

#43
post #13

Earlier quoted context omitted.

The tl;dr is that instead of representing emails as type String and manually sprinkling is_email(str) throughout your code, you represent as type Email, which has a function parse(String) -> Option . The type system then ensures the checks are present whenever they have to be, and nowhere else. This is extremely natural to do in a language like Haskell or Rust. And incredibly unnatural to do in C++ for instance.

I hope this is not trolling so I'll bite. It is incredibly natural to represent an object, such as an email, as an Email class in object oriented languages like C++. It'd then have a constructor that accepts a string and constructs the email object from said string, or maybe a parse(string) -> Option thingy. The type system then ensures the checks are present whenever they have to be, and nowhere else. Tl;dr: there's…

Well, in C++ the constructor must return a value of its class type - you can't return an Option from a constructor on T, for example, and since constructors are the canonical way to construct an object, it creates stylistic and idiomatic friction when you start using free functions to create a Maybe instead of constructors.

Re: "Parse, don't validate" through the years with C++

#44

It seems like the C++98 example is the best by far? Keeps all error information while remaining concise and easy to understand. Not to mention 50 times faster. (Could be improved by adding some simple type aliases like BirthYear that explicitly start from 1900.) IMO the main takeaway is that malformed input is not an exceptional state when parsing, and should be treated as a first class citizen. Everything else is ya…

The compile time is 50 times faster, not the runtime.

Re: "Parse, don't validate" through the years with C++

#46

The C example could have implemented a lot of validation just by checking the return value of sscanf(): if (sscanf(user_input, "%4u-%2u-%2u", &year, &month, &day) != 3) { // return an error } This still does not catch trailing garbage, but you could check for that as well: if (sscanf(user_input, "%4u-%2u-%2u%c", &year, &month, &day, &dummy) != 3) { // return an error } The result would be 4 if there was at least one…

Although it feels intuitively as though a std::scan could make sense, it doesn't, at least not with the sort of API I've seen suggested Consider a hypothetical Goose type, we can express any Goose usefully as output and, conveniently, some potential inputs could be read as a Goose successfully though most arbitrary strings cannot be understood as a Goose. Providing std::print for Goose is simple, we've got a variable…

Rust's FromStr only deals with parsing a single object. However, ideally std::scan() would be an exact counterpart of std::print() and would be able to parse multiple objects. I totally agree that the C way of passing references to already existing variables is not great. Ideally you return a tuple of objects, but then it becomes very annoying to specify the types. Maybe something like this?

    auto [value, text, goose] = std::scan(input, "{} {} {}");
A halfway solution would be to have the hypothetical std::scan() take references to std::optionals or std::expecteds:

    std::optional value;
    std::optional text;
    std::optional goose;
    /* auto result = */ std::scan(input, "{} {} {}", value, text, goose);
The latter would be type safe, close to how scanf() works, but less satisfying from a functional programming standpoint.

Orthogonal to that, adding support for scanning a Goose would be just like how you add a formatter for it, and would be quite similar to a Rust trait. One could imagine having to define something like this:

    template
    struct std::scanner {
        constexpr auto parse(std::format_parse_context& ctx) {…}
        auto scan(std::format_context& ctx) const -> std::optional {…}
    };

Re: "Parse, don't validate" through the years with C++

#47
post #11
post #4

Author has used LLMs to generate Java code in C++. It detracts from his point.

What Java code? Regardless of how they might have used LLMs, I tend to have an issue with this kind of complaint, given the C++ example code on the Design Patterns: Elements of Reusable Object-Oriented Software book, released in 1994, 2 years before Java was made public. Or the examples from "Using the Booch Method: A Rational Approach", "Designing Object Oriented C++ Applications Using The Booch Method", or "Using t…

> What Java code?

A class with a passel of static member functions is Java code. It is not in any way idiomatic C++ code which has had namespace-level ("free") functions since it was invented as C-with-classes many decades ago. Using classes holding a whole lot of static member functions is strongly frowned on in the professional C++ community.

Re: "Parse, don't validate" through the years with C++

#48
post #47
post #11

Earlier quoted context omitted.

What Java code? Regardless of how they might have used LLMs, I tend to have an issue with this kind of complaint, given the C++ example code on the Design Patterns: Elements of Reusable Object-Oriented Software book, released in 1994, 2 years before Java was made public. Or the examples from "Using the Booch Method: A Rational Approach", "Designing Object Oriented C++ Applications Using The Booch Method", or "Using t…

> What Java code? A class with a passel of static member functions is Java code. It is not in any way idiomatic C++ code which has had namespace-level ("free") functions since it was invented as C-with-classes many decades ago. Using classes holding a whole lot of static member functions is strongly frowned on in the professional C++ community.

Certainly not the professional C++ comunity that still uses frameworks born in the 1990's predating Java, or game engines.

Re: "Parse, don't validate" through the years with C++

#49

Heh, I can especially tell the first code example is LLM-generated. Humans don't usually write comments like: // There are a few ways to let API callers bring their own // memory, as they would in a no-malloc environment and this // stack-friendly c'tor is a stand-in for that. There's just something about this comment that doesn't feel right. I've seen these kinds of phrasings in LLM output before but I'm not sure ex…

Author here. The post didn't get much traffic when I uploaded so I didn't engage much with the thread. Looks like I should've come back!

I specifically wrote that by hand to note the specific shortcomings of this approach when evaluated under King's thesis. I do acknowledge that I use LLM models heavily when drafting the code snippets in this blog post, and I do a mini review in the conclusion of the downsides of using these models.

Re: "Parse, don't validate" through the years with C++

#50
post #45

I'm not a Haskell programmer, but from my limited awareness: Wouldn't they want to encode the restriction that April 31 doesn't exist directly in the type system instead of using raw integers for the underlying struct?

A very specific shortcoming of this implementation is indeed "Day of Month" and "Month of Year" aren't given their own types! The type specification should likely be applied all the way down! I felt the examples conveyed the point well enough and it was shorter in many cases.
Post reply on HN