Hacker News

Top stories

Live mirror
30 storiesupdated just nowView source snapshot
  1. "They had no concept of a duty of care to their users." (aresluna.org)
    130comments
  2. In an $80 Motel Room, a Discovery to Shed Light on the Origins of Life (nytimes.com)
    20comments
  3. The Normalization of Inexplicable Failures (ihatethefuture.com)
    2comments
  4. Replacing the old battery on rechargeable bike lights (jvns.ca)
    21comments
  5. Show HN: TinyAIArena watch AI agents battle it out (tinyaiarena.com)
    2comments
  6. Writing Efficient C++ Code (asawicki.info)
    5comments
  7. Font where each token is equal-width (twitter.com/amplifiedamp)
    6comments
  8. Ten Lines of Code That Changed My World (pixelambacht.nl)
    3comments
  9. Flip Fluid on Flip Dots (mitxela.com)
    18comments
  10. Show HN: A CC0 museum of retro 3D tricks you can paste into a page (3d-retro.com)
    8comments
  11. Fakecloud: Local AWS cloud emulator for integration tests (fakecloud.dev)
    25comments
  12. Does Georgism work? Five years later (astralcodexten.com)
    362comments
  13. Unsealed Briefs in Authors’ Case v. Microsoft/OpenAI (authorsguild.org)
    482comments
  14. Finally, A True Blue Rose Exists (sciencenews.org)
    27comments
  15. Go Concurrency Distilled (antonz.org)
    134comments
  16. postmarketOS Rebrand: Nura (nura.eco)
    —discuss
  17. PipePipe: NewPipe hard fork implementing SponsorBlock (github.com/infinityloop1308)
    249comments
  18. Walgit: A Git server that is one binary in front of an object store (github.com/rgodha24)
    1comments
  19. Rusty thoughts on "Parse, don't validate" (thegreenplace.net)
    12comments
  20. DeepSeek Elastic Compute (DSec) (arxiv.org)
    95comments
  21. Show HN: Reladraw – A diagram language where you decide where to place things (github.com/reladraw)
    96comments
  22. The internet discovers TLA+. Now what? (reasonable.io)
    42comments
  23. 10 Tells of a Slop UI (hereticpleb.vercel.app)
    135comments
  24. ASML says it sold 'absolutely nothing' in Europe in 2026 (tomshardware.com)
    798comments
  25. Biology might not be quantum, but its math is quantumlike (quantamagazine.org)
    43comments
  26. "As a Language Model": Chat Template Switches LLM Self-Referential Voice (arxiv.org)
    92comments
  27. A searchable library of forgotten public-domain film clips from 1915 onward (movingimagearchive.com)
    26comments
  28. Fifteen years later, the Apple Cards origin story (lexontech.org)
    110comments
  29. An agent used DNS to reach an external chatbot (alignment.openai.com)
    142comments
  30. Exploding variance of means of exponentials: least-squares to the rescue (francisbach.com)
    —discuss

Rusty thoughts on "Parse, don't validate"

35 pointsby 7h agoeli.thegreenplace.net
12 comments
2h agoHN ↗

Good article on Rust's strengths with types. If you like this, you may be curious how you might build your own parse capabilities. I like the Rust crates Winnow and Nom, and also the Rust traits From and Into.

1h agoHN ↗

Nonempty type wrappers are a stark reminder that we are missing out on refinement types.

1h agoHN ↗

I was thinking about its implementation, too, and ended up deciding that it was probably a performance optimization.

`Vec<T>` stores all data on the heap, so getting anything out of it involves a pointer deref and possibly also an array bounds check. This `NonEmpty<T>` type keeps the first element of the list in a location that supports some low-level optimization that might make a significant difference in situations where accessing the first element is much more common than accessing subsequent elements.

1h agoHN ↗

Rust has a proposal for this, in the form of pattern types. It's on nightly, but quite far from being ready for prime time.

1h agoHN ↗

This is great. Alexis King actually stated that, had she known how popular “Parse, Don’t Validate” had been, she would have written it in a language more widely used than Haskell.

1h agoHN ↗

With its rich type system, Haskell is the perfect language to demonstrate the dictum.

33m agoHN ↗

With its crap type system Python might be even better, in a strange way.

Haskell's strong, static, non-reflective type system tends to make "parse, don't validate" produce code that also looks nicer. Which is great. So great that it steals a bit of the main message's valor.

In Python, though, it's really easy to just let your data be a dynamically typed list of dicts forever. So easy that parsing into something more strongly typed looks like a whole lot of extra effort. Upon looking at that sort of thing many a working Python programmer, myself included, hears the voice of GvR murmuring disparaging things about "academic" programmers down in the pit of their brain.

Which creates an opportunity to demonstrate all the ways the (arguably) more Pythonic way is actually a royal PITA when you try to make your code robust. Handling and reporting data validity errors gets scattered all over the code, which makes it annoying to maintain. Unit test suites get bloated because it's not obvious what inputs a function should be able to handle. Comments and docstrings to help keep track of this stuff begin to proliferate.

1h agoHN ↗

Another take, from the primary example: This is what `unwrap()` is for. I understand that the author is looking at this from a correctness and safety(?) perspective. For practical purposes, I would unwrap here. If it's less trivial than the example, unwrap with a comment explaining why it's fine.

Another angle: Unfortunately, the `first()` method being fallible here is just an issue of using an imperfect method/datatype here. This is where the author gets in to a non-empty-vec custom type. Then you are balancing using a more correct type that takes custom wiring vs a std lib thing everyone understands and takes no setup. I would lean towards this setup if I were using this non_empty_vec.first() unwrap pattern a number of times in the code base; then the setup would be worth it, at least for my own code bases. If I were exposing this in a lib others would use, I would keep the standard Vec so as to be more transparent for others.

In both views: "This is what unwrap is for" does it for me in all cases I've encountered to date. Maybe for aerospace or safety critical systems, I would have a different take.

A third take: I notice this trend in the rust community. It's not my cup of tea. Keep things simple, easy to maintain, and don't let "correctness" get in the way. In this example, I don't think it gets in the way, but I have seen this mindset lead to it getting in the way, especially in embedded, where mapping the Owernership model to hardware ends up in messy patterns and surprising assertions about embedded-101 concepts like DMA being "unsolved", "no good way", "difficult" etc.

Rust provides tools to make sure specific logic is correct if it passes the compiler. People sometimes go overboard and assume you have to type-maxx your code, regardless of complexity added by doing so.

34m agoHN ↗

...I'm so happy that I write in untyped languages so I don't have to deal with any of this.

31m agoHN ↗

But you kind of do.

For a untype language like js array, since it can be empty, you have to either always check the length, the item returned, or have a precondition to know the array is not empty.

All three of those cases is either code or context you’re holding in your head.

All that stuff is equivalent to a type system

33m agoHN ↗

Not sure that type is good advice:

    pub struct NonEmpty<T> {
        pub head: T,
        pub tail: Vec<T>,
    }

You'd have to manually implement the traits to support the ergonomics of slices and iteration and costly reallocation if you need to pass ownership as a Vec:

I'd expect:

    pub struct NonEmpty<T> {
        v: Vec<T>,
    }

The constructor would enforce the invariant and then you'd impl Deref and DerefMut for [T] to gain normal len/is_empty/indexing/iteration, passing as &[T] to other funcs and mutating values (which can't break the invariant).

To mutate length while preserving the invariant it's dealers choice e.g.

- add .into_vec() for unwrap/mutate/rewrap

- add invariant preserving mutators of your choice

13m agoHN ↗

Which deref must I use to get most of the existing interface sans `retain()`?