Live data from Hacker News

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

cekrem.github.io

81–90 of 107 posts

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

#81
post #66
post #45

Earlier quoted context omitted.

I haven't done a lot of Typescript, but I've done at least a couple of month's worth now, and every time I have to type "as" my inner Haskell programmer screams. If I could add one feature to Typescript it would be something like "as" that actually validates the result against the type system and can fail. Unfortunately, that's way, way easier said than done. It's the bad type of keyword that has unbounded runtime co…

"every time I have to type "as" my inner Haskell programmer screams." - most of the times you don't have to. You choose to. "If I could add one feature to Typescript it would be something like "as" that actually validates the result against the type system and can fail." - I don't think it's fair to expect that since most of the statically typed languages will not guarantee things in runtime unless you specifically r…

"I don't think it's fair to expect that since most of the statically typed languages will not guarantee things in runtime unless you specifically run a validation code in runtime."

If I have a value of type X in a static language, then I know that it absolutely conforms to the layout of type X. It isn't even that we have to provide a "validation function", it is that it is quite literally physically impossible for my value to not conform to the definition of type X, in the languages like C or Go or Rust where the type layout is actually a specification of a layout of data in memory. If I have JSON '{"a": 1}', there is no way whatsoever to stick that in a "struct { A string }", because it physically doesn't fit. By "physically", I mean, in RAM, in the physical cells and voltages. There's no way to validate that a "struct { A int }" 'really contains an int' because there is no way for it to be anything else.

Typescript specifically has these issues because all of its objects boil down to a Javascript object with certain keys, and all of the values are ultimately of type "any" no matter what Typescript tries to lay on top of it. If I have this sort of data come in to a static language, I have to have a step where it very deliberately converts it down to the static representation. There isn't an equivalent of "as". Modulo unsafe, but we don't count unsafe in these sorts of discussions.

I am absolutely guaranteed in a static language that if my struct says field "A" is an int, it absolutely, positively is, always has been, and always will be.

The main problem I encounter with "as" is when I have external data coming in. For that I have zod and validation functions. What prompted my post is my experience yesterday where I corrected an AI using "as" (which it used because a lot of its training data does this) and had it call an actual validation function that I happened to already have before it cast it into the type. But the reason my Haskell programmer screams inside is that a validation function can still be wrong, because the compiler isn't helping me. In a static language, I can guarantee that if I have "I dunno, some JSON value" on one side and a struct comes out the other end with some value derived from it, I have absolutely had some bit of code check that and pack it into the static value in a way that the compiler has helped check. I can further reliably compose these promises quite reliably through further type specification in my static type.

A validation function can still have bugs in it that a static language compiler would have strictly, compile-time validated. It's better, but it's still the manifestation of the quite accurate criticism that dynamic languages end up trading away all their convenience with not specifying types with having to have vast swathes of validation, and testing of that validation, in the testing backend. In Typescript, I can mostly sorta kinda compose them together, but it takes a lot more features and grease and effort. I appreciate Typescript in its capacity as taming Javascript and prefer it substantially over Javascript alone, it's probably the best thing of its type that we could hope for, but if I consider it as a language that stands alone, I really really dislike it.

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

#82

Earlier quoted context omitted.

While I would much prefer to only write Typescript types, this would drive me insane: > The only thing I do on top of that is to use annotations like "@minimum 0" (or, in the email example, "@format email") where the base types are not enough, but those simply go inside comments.

Obviously it's not ideal, but IMO it's the better option. Much better than `z.number().integer().min(0)` or whatever zod equivalent there is and then have to deal with the inferred types which among other things tend to suck for IntelliSense etc. Those annotations map directly to JSON Schema attributes.

You can AOT typescript types from zod schemas if intellisense is your main complaint. I think it generally makes more sense to transform from more expressive => less expressive, and zod is more expressive than typescript (as evidenced by your need to add doc comment annotations to get similar behavior going the other way).

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

#83
I always felt a little duped whenever I tried coding in TypeScript. You get zero runtime type safety guarantees, plus it's often harder to tell in TypeScript whether the transpilation will result in an efficient and performant implementation. Maybe the worst thing is that if you have two objects, one called EmailAddress and one called UnrelatedThing, but both have a UUID as the first thing and a string as the second thing, and now you create an object at runtime that is called TotallyUnrelatedThing that has a UUID followed by a string, the runtime sees EmailAddress, UnrelatedThing, and TotallyUnrelatedThing as being structurally identical and in fact they are all "compatible" under TS at runtime, which is usually the exact opposite of what one would expect. Now in other languages you can get some additional guarantees like in C# at the cost of more ceremony and boilerplate to establish all your abstract primitives and layers.

My own approach is mostly to prefer JS and JSON objects with helper chains including validators and constructor/builder and parser utilities. Get the age from the user and get the domain from the email address and don't be surprised by the type, because everything is an object, and don't be surprised that you need to validate and parse, but expect to do so always. Do it in as modular and reusable a pattern as makes sense, which often isn't exactly the same for every scenario, but that's OK. Speaking of which, am I the only one who thinks it's usually more of a hassle than it's worth to define a universal EmailAddress for all times and places? Often the conflict happens because even if I try to do so, I usually am using one vendor as an IdP and a different vendor for transactional emails (even if I use the same cloud provider say for both). They each probably have different robust regex implementations to check whether something is truly an email address. I then still need authEmailAddrees and billingEmailAddress objects to pass to each, respectively, but there is no enforcement or requirement to instantiate an interface that contains an enforceable contract in TypeScript, so remind me why I am bothering to say these things are both email addresses? It just always feels like the worst of all worlds when I work in TypeScript, kind of a "rules for thee but not for me" situation. I have to follow typing, but TypeScript doesn't quite have to do so. In particular it always feels like I still have to enforce a lot more validation at the API layer than should be required, without any feeling that I can trust an EmailAddress to instantiate an IEmailAddress interface or that AuthEmailAddress and BillingEmailAddress inherit from the base EmailAddress or that those structures are guaranteed to persist at runtime and that a TotallyUnrelatedThing that just so happens to have a UUID plus a string but isn't strictly instantiating the email class will never accidentally end up populating an email field, which is kind of a concern. (By the way I think the hardcore email address validation really ought to be handled by the upstream provider anyway. I just do some minimal checks on length and presence of dots and at-symbols but don't bother trying to implement a full regex compendium of all email possibilities since these details frankly conflict frequently enough at the edges that I would rather let my IdP and email providers decide for themselves if they truly have an acceptable email input, and handle the failure loudly and up front, rather than try to do all the gatekeeping myself.)

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

#84

default: { const _exhaustive: never = result; return _exhaustive; } ...is not how people should implement an exhaustiveness check ever! An exhaustiveness check exhausts your knowledge about the world, it should throw an exception at runtime. Just return ing the non-matched case is a recipe for disaster. Do this instead: default: ((value: never) => { throw new Error(`Missing case for value: ${value}`); })(result);

The original author is correct. Their implementation of an exhaustive check will give you a compiler error if you miss a variant in your switch statement. I much prefer a compiler error over a run time error. It's even recommended in the official typescript docs - https://www.typescriptlang.org/docs/handbook/2/narrowing.htm...

> Their implementation of an exhaustive check will give you a compiler error if you miss a variant in your switch statement. I much prefer a compiler error over a run time error.

What are you talking about? You'd still get the compile error just the same.

Falling back on returning the input argument doesn't even make sense in the typescript docs:

  type Shape = Circle | Square;
 
  function getArea(shape: Shape) {
    switch (shape.kind) {
      case "circle":
        return Math.PI * shape.radius ** 2;
      case "square":
        return shape.sideLength ** 2;
      default:
        const _exhaustiveCheck: never = shape;
        return _exhaustiveCheck;
    }
  }
Case circle and square are returning a number, but an unknown shape is returning itself? This is especially annoying when teammates are starting to cast values into a Shape throughout the codebase. Guess I'll need to make a PR to the typescript docs.

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

#85

Earlier quoted context omitted.

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 na…

> Strings narrow honestly. This is a great example of the latest "LLM tell" I'm seeing in prose. It's so terse with its "power-verb" that I have to read it multiple times. It's a clever compaction of English, not something I want to read outside of a headline or motto. Here's another example from a Claude convo I had open: "Alerts flag mirrors". It's agreeing with my proposal that the alert system should be expanded…

[dead]

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

#86
post #78

I don't like zod. I want to define my types, not write schemas. And I don't like that then I have to use the types derived from those schemas rather than types I've defined myself directly. So I just define my types and then use typescript-json-schema or similar to build a JSON Schema at build time (i.e. from an npm script) which then I use to validate input using ajv. The only thing I do on top of that is to use ann…

What you're doing is essentially what Zod is designed to avoid. If you tolerate needing a separate build step more than having to define types with Zod's syntax, then it makes sense not to use Zod since it's not made for you.

To me the build step is a good thing. It's a simple script in npm, and it means I only keep what I need (the JSON Schema, which I don't need at dev time) in runtime and whatever package generates those schemas out of TS types can remain as a dev dependency.

zod can't be a dev only dependency, and you have to deal with breaking changes and maybe switching to a completely different library in a few years (joi, with a syntax very similar to zod's, was very popular a while ago too).

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

#87
I found that having clean models and parsing your data using Zod religiously at the application boundary (requests, URL, DB, env) gets you 80% of the way without fighting the language.

The stray email: string causing trouble is fine and is less work than self-imposed constraints that will be worked around by others.

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

#88

Earlier quoted context omitted.

> if the content is being hosted via AWS vs some non-magacorp > power being used by the data center is renewable That doesn't change anything about the content itself. AI writing is a disservice to the reader. Why should I even care to read an article you didn't even care about writing yourself? At this point a 300-character tweet would've achieved the same effect.

That’s my point. The AI writing either affects the content or it doesn’t. If you require a disclaimer to tell the difference, then it isn’t affecting the content. Requiring a disclaimer is essentially admitting the content isn’t meaningfully different than human generated content. At that point, who cares? Just engage with the premise on its own merits, rather than on how it was written.

> Requiring a disclaimer is essentially admitting the content isn’t meaningfully different than human generated content. At that point, who cares? Just engage with the premise on its own merits, rather than on how it was written.

The problem is the reader has to invest time to find out and LLM written text will (on average) lower the quality towards "meh" and spend more words doing so. Even if the author is making an earnest effort to produce high quality content, they need to admit to themselves and others that their results will be more hit or miss. The disclosure allows the reader to make a more informed decision about how to engage with the material (e.g., have an LLM summarize or analyze the content, or just dive in because we know it will very likely be a good read). Editing what someone has written is like reviewing code, you're by default not as invested, so the results will likely reflect that reality.

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

#89

Zod is by far the most ergonomic way to express those ideas in TypeScript these days. I miss it when writing code in other languages. The friction with the rest of the ecosystem is real, though. Most code out there expects you to handle errors with exceptions. I get the impression that polymorphic return types could get in the way of JSC/V8/SpiderMonkey's JIT, but I haven't measured it and I'm not sure of the actual…

> Most code out there expects you to handle errors with exceptions.

Because you have to build the Option/Result/whatever system yourself, and propagating and unwrapping isn't fun.

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

#90
post #21
post #19

Earlier quoted context omitted.

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?

Should they disclose the use of a spellchecker? A translation app? Gramarly? A writing tutor?

It used to be the polite thing to disclose that you used a translation app. In fact, traditionally, you disclose when you translate anything so people know the context in which to interpret your text.

In the same way, I wanna know if a book is written by some famous people just ghost written.

Of course, the point is moot. Somebody using AI to write a blog post is unlikely to be self conscious enought to thing it's necessary to disclose it in the first place.

Post reply on HN