Live data from Hacker News

Parse, Don't Validate – In a Language That Doesn't Want You To

cekrem.github.io

31–40 of 107 posts

Re: Parse, Don't Validate – In a Language That Doesn't Want You To

#31
post #15

We should make authors disclose how much AI was used to write an article. This reeks of Opus 4.8.

Why should they disclose how much AI was used to write an article?

Because I would've completely avoided the article if I knew that I would be served slop. I was interested in the content, but I was immediately thrown off by the writing style, which closely resembles what I've been getting from Opus 4.8 lately in my dev work. Filler language and useless metaphors everywhere.

> Booleans look tidy until somebody adds a third case and exhaustiveness silently doesn’t kick in. Strings narrow honestly.

Like, nobody truly writes like that. It wouldn't get past any competent editor.

Strings narrow honestly? What does that even mean? This kind of 3-word precision is useless and they appear everywhere in the article. We get the point with in the first sentence, no need to add more.

Re: Parse, Don't Validate – In a Language That Doesn't Want You To

#32
post #22

"TypeScript is structurally typed, which means two types with the same shape are the same type. string is string is string" I don't speak typescript so am probably missing something obvious. but. why would you parse an email(or anything really) into a string? (or string equivalent) When parsed it will end up as a specific email object, that is, something closer to a C struct. What is the articles dance doing?

Javascript doesn't have structs. The idea is that you have data on one hand and you have type witness about that data on the other hand. Type witness is something for the type system. But here you encounter the limits of structural typing versus nominal typing, because structural typing isn't able to witness that directly.

In sufficiently strong nominal type systems, I can hide the constructor for an EmailAddress type (as in: nobody can just construct an EmailAddress type). In Haskell speak, I can then export a function parseEmailAddress = rawString :: string -> EmailAddress. The function parseEmailAddress is the only place that has access to the constructor. Which means that the only way to turn a string into an EmailAddress is by calling parseEmailAddress.

Note that at runtime EmailAddress is just a string. The boundaries live in the type system, not on the value level. A structural typing system (as in TypeScript) does not enable that, it forces you to turn EmailAddress into something else than just a string.

Are you confusing Email vs EmailAddress? I think that in many cases people would prefer EmailAddress to be represented as a dumb string at runtime. But if you don't, you will easily find other examples where you have 2 structurally similar types, that you don't want to mix up.

Re: Parse, Don't Validate – In a Language That Doesn't Want You To

#33
This is just validation that is using the type system to indicate the validation has already occurred. I think the real point of “parse, don’t validate” is to make the type system give you structural guarantees that couldn’t exist otherwise (e.g. always having a first/last element in the NonEmpty example from the original article). If you’re just branding the types as “parsed” (in reality, simply validated) you still have to know that the invariants you care about hold when using the “parsed” type (e.g. splitting the email type using “@“ will always yield 2 elements), instead of the structure of the type holding that info inherently (e.g. struct Email { name: String, host: String }).

Re: Parse, Don't Validate – In a Language That Doesn't Want You To

#34

We should make authors disclose how much AI was used to write an article. This reeks of Opus 4.8.

I recently made a Firefox Extension to mark authors as Slop for the same goal but not the same reason.

I don't think disclosing helps here. If the article wasn't obviously generated, why would that affect you ?

The only issue I have is being half-way through the article and realizing I am reading hallucinated text. If I can mark the author once, I won't see them again. This works fine for me. You could argue that disclosing would fix this issue, but the issue is not that AI was used, but that it was not curated.

Re: Parse, Don't Validate – In a Language That Doesn't Want You To

#35

I personally love the idea and concept, but struggle to apply to real projects. Suppose I have a User with some attributes like birthday, email and whether they have been verified. in common codebase, you can see `if (user.verified_at != null)` or something along the lines, in case of parsed code I do feel like I should have types for each of them (or interfaces): - UserWithBirthday - VerifiedUser, UnverifiedUser - U…

The computer-science answer to this problem are called "refinement types", where you can attach arbitrary predicates to a type, e.g. (pseudo-code):

    fn send_birthday_mail(user: {u: User, u.birthday != null})
Contracts are a similar solution that restricts the predicates to only appearing in function types.

The difference between this and an assert is that it gets checked at compile time (it can get quite expensive to do the check though).

What can you do in mainstream languages? As much as is worth and no more than that. String -> User is worth it, User -> UserWithBirthday is not.

Re: Parse, Don't Validate – In a Language That Doesn't Want You To

#36

The author found out about the square holes in round peg situation with TS. Functions can implicitly error, and there's no annotation that's enforced to tell you that it might error. FP solves this with Result/Option, but this doesn't fit in TS. Effect is there to find a solution but will fail. Zod is the acceptable middleground in my opinion. Zod will allow you to throw a schema against an object and it'll tell you…

> Effect is there to find a solution but will fail.

What do you mean?

I'm into Effect from long time and it really scales well the more complex your applications.

Schema is way more advanced than Zod by the way, both at type level and functionality it has a proper decoder/encoder architecture.

You can encode "this isn't just a string -> non-empty-string -> valid email pattern" but a confirmed email the user has clicked on at the type level, by leveraging effectful schemas (and durable workflows if you want).

You may not need it 99% of the time, I myself rarely use that, but it's not a fair comparison.

Zod is more ergonomic, has easier apis and is perfect for most users. Would not recommend schema unless one buys the whole package.

Re: Parse, Don't Validate – In a Language That Doesn't Want You To

#37

I personally love the idea and concept, but struggle to apply to real projects. Suppose I have a User with some attributes like birthday, email and whether they have been verified. in common codebase, you can see `if (user.verified_at != null)` or something along the lines, in case of parsed code I do feel like I should have types for each of them (or interfaces): - UserWithBirthday - VerifiedUser, UnverifiedUser - U…

I think this is the wrong pattern in this instance. You parse an email or phone number because validating leaves it as a plain string, and you lose the context to know for sure if that string is actually an email or phone number.

In your instance, you could have:

  type User = {
    // ... rest of fields
    email: {
      verified: boolean,
      // branded type here ensures that this string is a proper email address
      value: EmailAddress,
    },
    birthday: Date | null,
  };
In this instance, your logic with a method that accepts birthday and email has all the information it needs to make its choice.

Re: Parse, Don't Validate – In a Language That Doesn't Want You To

#38
post #5

This feels right, and I also have never done it (or had the guts to get others to do it). The reason I've not is - say there's an optional field. Currently we call that null, probably, and check each time if it's there or not. I could instead make a type, like User and UserWithPhoneNumber. Should we be making types for each combination of present/absent fields? That can't be right. The classic answer is to move the l…

I think this is a slightly different problem. The absence of an optional field, if that's a legal state, is meaningful every time you use the type, so you encode it on the field: `phone: ValidPhoneNumber | null`. When it's not null you're still guaranteed a valid phone number. When it is null, that's a legal state you have to handle and which is domain logic, not validation you forgot to do. The combinatorial explosi…

That's fair enough - I see what you mean. I think I read the case I was thinking into the article. Now I re-read it, it is saying what you're saying, which does make a lot of sense.

Using types like this also means you can more easily avoid assignment errors, as everything will have a very specific type (e.g. Age instead of int).

Re: Parse, Don't Validate – In a Language That Doesn't Want You To

#39
post #19
post #15

Earlier quoted context omitted.

Why should they disclose how much AI was used to write an article?

If nothing else, it should be done as a courtesy to those who would like to avoid such content. If the result is better for having used AI, why wouldn't an author want to disclose it?

I think the need to jump through hoops to disclose anything and anything that might offend someone’s particular sensibilities is a losing battle. What if I want a disclosure on if the content is being hosted via AWS vs some non-magacorp that agrees with my sensibilities more? Or that the power being used by the data center is renewable? Or a disclosure for the author’s every political position so I know if I agree with them and if I should amplify their message and/or generate ad revenue through their site?

At the end of the day, the ideas within the content are what matters. An idea has or does not have merit regardless of if it was produced entirely by a person, or by a person using AI as an editor, or 100% generated by AI. If you need a disclosure on if an idea was produced by AI, you are saying that you have no interest on debating the content on the grounds of the arguments it is making, while simultaneously ceding you can’t tell the difference between someone using AI and someone who isn’t (which undermines one of the primary arguments against AI, that it makes for inferior outputs).

Re: Parse, Don't Validate – In a Language That Doesn't Want You To

#40

This is just validation that is using the type system to indicate the validation has already occurred. I think the real point of “parse, don’t validate” is to make the type system give you structural guarantees that couldn’t exist otherwise (e.g. always having a first/last element in the NonEmpty example from the original article). If you’re just branding the types as “parsed” (in reality, simply validated) you still…

"This is just validation that is using the type system to indicate the validation has already occurred. I think the real point of “parse, don’t validate” is to make the type system give you structural guarantees that couldn’t exist otherwise (e.g. always having a first/last element in the NonEmpty example from the original article)."

It's the same thing. In the latter case, something has validated that your NonEmpty has a first and a last element. It's all validation before you stick it in a type that asserts that the validation is guaranteed to have occurred so every function receiving it doesn't need to do it itself.

Any non-trivial use of a type system will involve making guarantees the type system itself can not actually express [1]. There's nothing wrong with saying "this is a valid email in accordance with my standards" in a type. Merely using the type system to assert "I have some sort of value in the name and host fields" is valid but a degenerate use. "struct Email { name: Name, host: Hostname }" is an even stronger use of the type system, where Name and Hostname are themselves values you can only get by passing some incoming string through a validation process. Asserting that these things exist is just the most basic check possible, but your type still permits {name: "\0\0\0\0\0\0", host: "!"}, whereas under my definition, assuming that Name and Hostname are reasonably defined, that value will not be ever be something that can be witnessed.

In fact in general, while I don't absolutely rigidly apply this, especially in smaller script-like programs, when a "string" appears in my strong types that specifically means "this has unbounded contents". It's an appropriate type for "stuff I got off a network" or "stuff a user typed". What stuff? Don't know. Haven't checked it yet. When I do it'll get a more specific type like a Username or DecodedUTF8String or something else. Thanks to people using way too many "strings" and "ints" in the world I have to constantly explain to my LLM that I want stronger types. I'm yet to find the invocation to put into my CLAUDE.md or equivalent to get it to do it right the first time consistently.

[1]: With a wistful stare into the distance acknowledging the theoretical utopia of dependent types... but it doesn't seem to be coming down from "theoretical" any time soon.

Post reply on HN