←back to thread

Parse, Don't Validate (2019)

(lexi-lambda.github.io)
389 points melse | 1 comments | | HN request time: 0.26s | source
Show context
seanwilson ◴[] No.27640953[source]
From the Twitter link:

> IME, people in dynamic languages almost never program this way, though—they prefer to use validation and some form of shotgun parsing. My guess as to why? Writing that kind of code in dynamically-typed languages is often a lot more boilerplate than it is in statically-typed ones!

I feel that once you've got experience working in (usually functional) programming languages with strong static type checking, flakey dynamic code that relies on runtime checks and just being careful to avoid runtime errors makes your skin crawl, and you'll intuitively gravitate towards designs that takes advantage of strong static type checks.

When all you know is dynamic languages, the design guidance you get from strong static type checking is lost so there's more bad design paths you can go down. Patching up flakey code with ad-hoc runtime checks and debugging runtime errors becomes the norm because you just don't know any better and the type system isn't going to teach you.

More general advice would be "prefer strong static type checking over runtime checks" as it makes a lot of design and robustness problems go away.

Even if you can't use e.g. Haskell or OCaml in your daily work, a few weeks or just of few days of trying to learn them will open your eyes and make you a better coder elsewhere. Map/filter/reduce, immutable data structures, non-nullable types etc. have been in other languages for over 30 years before these ideas became more mainstream best practices for example (I'm still waiting for pattern matching + algebraic data types).

It's weird how long it's taking for people to rediscover why strong static types were a good idea.

replies(10): >>27641187 #>>27641516 #>>27641651 #>>27641837 #>>27641858 #>>27641960 #>>27642032 #>>27643060 #>>27644651 #>>27657615 #
ukj ◴[] No.27641651[source]
Every programming paradigm is a good idea if the respective trade-offs are acceptable to you.

For example, one good reason why strong static types are a bad idea... they prevent you from implementing dynamic dispatch.

Routers. You can't have routers.

replies(3): >>27641741 #>>27642043 #>>27642764 #
kortex ◴[] No.27641741[source]
Sure you can. You just need the right amount of indirection and abstraction. I think almost every language has some escape hatch which lets you implement dynamic dispatch.
replies(1): >>27641809 #
ukj ◴[] No.27641809[source]
This is a trivial and obvious implication of Turing completeness. Why do you even bother making the point?

With the right amount of indirection/abstraction you can implement everything in Assembly.

But you don't. Because you like all the heavy lifting the language does for you.

First Class citizens is what we are actually interested in when we talk about programming language paradigm-choices.

https://en.wikipedia.org/wiki/First-class_citizen

replies(3): >>27641950 #>>27641980 #>>27641983 #
kortex ◴[] No.27641950[source]
I mean, GP said "you can't have routers" and maybe I'm being dense by interpreting that as "never or almost never," but even with a generous "too hard to be practical," I still don't think it's correct.

And I explicitly said "escape hatch" meaning language feature. You don't need that much indirection to get routers in Haskell, Rust, Go, C, C++... like I fail to see how implementing routers are a barrier in strict type system languages.

Is it easier in python or js? Sure. can't? hardly.

E: here's some vtable dispatch (unless that doesn't count as "dynamic dispatch") in Rust. Looks really straightforward.

https://doc.rust-lang.org/1.8.0/book/trait-objects.html

replies(1): >>27651184 #
ukj ◴[] No.27651184[source]
What C++, Haskell, Rust, Go etc. call "dynamic dispatch" is what a router calls "static routing". The defining characteristic is that the lookup table is pre-determined and immutable at runtime.

What routers call "dynamic routing" is having the lookup table mutable at runtime.

There can be no equivalent to that in type-safe languages because when you mutate the dispatch table you lose type-safety.

replies(1): >>27652121 #
kortex ◴[] No.27652121[source]
> What routers call "dynamic routing" is having the lookup table mutable at runtime.

> There can be no equivalent to that in type-safe languages because when you mutate the dispatch table you lose type-safety.

That's exactly what I mean by escape hatches. Rust has unsafe. You can write a WTF FastInverseSqrt in Rust. You shouldn't 99% of the time. But you can.

Rust also has Box, Rc, Arc, and other tools. I'm not fluent enough in rust to know how to, but I'm quite confident and will eat my hat if you can't accomplish what is effectively a mutable vtable dispatch in Rust.

But also...why? Yeeting a function call into the void without any type knowledge seems way more bug-prone than interface/trait-based dispatch, to what benefit? Save developer time? I've spent countless dev-days of my life I won't get back debugging exactly this kind of dynamic-dispatched, json-dsl, frankly loosey-goosey untyped bullshit. There's so many better ways.

replies(1): >>27654964 #
ukj[dead post] ◴[] No.27654964[source]
Well isn't that's precisely my point!

"unsafe" turns off your compiler's guard rails.

You CAN accomplish mutable vtable dispatch and in doing so you will undermine Rust's type-safety!

Yeeting a function call into the void is what async network clients usually do. You will soon get a result. Maybe.

1. dang ◴[] No.27656856[source]
Would you please stop? Regardless of how right you are or feel you are, we don't want long, tedious flamewars like this and you did more than anyone else to prolong it. Dozens of comments is beyond excessive.

https://news.ycombinator.com/newsguidelines.html