Live data from Hacker News

Parse, Don't Validate (2019)

lexi-lambda.github.io

271–280 of 288 posts

Re: Parse, Don't Validate (2019)

#271
post #205
post #72

Earlier quoted context omitted.

> "A square is a rectangle" means "A square is a TYPE of rectangle" (at least, that is what I am parsing it as). In that case your former statement that 'The word "is" implies an isomorphism' seems to be wrong.

It may be wrong in your model/interpretation of my words, but it's not wrong in my interpretation of my words.

In what interpretation is it consistent for 'A square is a rectangle" means "A square is a TYPE of rectangle"' and 'The word "is" implies an isomorphism' to be simultaneously true? No matter how I cut it, the latter seems to prevent the former to me.

Re: Parse, Don't Validate (2019)

#272
post #16

Earlier quoted context omitted.

> The word "is" implies an isomorphism. Are you talking about a bijective mapping or are you saying it's a synonym for identical? Because the former doesn't make any sense here and the latter is not true. Red is a color does not imply that all colors are red.

I am talking about the polymorphic use of the verb "is" during the process of formalization. "Red is a color" can be formalized as "Red is a type of color" or "Red is member of set Colors". You can't formalize "Color is red" because it doesn't mean anything. When I say "Parsing is validation" I am using the verb "is" to mean an isomorphism.

Judging by all the other disagreeing comments, your in some sort of idiosyncratic context that only you understand.

Good luck with that.

Re: Parse, Don't Validate (2019)

#274
post #270
post #263

Earlier quoted context omitted.

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

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.

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

Re: Parse, Don't Validate (2019)

#275
post #265

Earlier quoted context omitted.

Agreed with the end of your post. However, the top post approaches religious dogma. I argue against that even if one has some good points.

> However, the top post approaches religious dogma. I don't deny it. Join the cult of Static Python. We have cookies! And lower stress levels! I usually wrap that spiel with my caveat "this depends greatly on your neurotype, style, environment, and other things." I have ADHD and my brain struggles with keeping bits of state in memory, so having to remember the type of every variable without my IDE tracking it for me…

Because it adds a lot of work that many projects don't need. Read wpietri's post on how candidates who write static get half as much accomplished in an interview.

Also since the tools are immature and bolted on afterward in Python, I think it's even a bit worse than it would be in something decent like C#.

Re: Parse, Don't Validate (2019)

#276

Earlier quoted context omitted.

> But in practice, they're just a bad match for projects where the defining characteristic is unstable ground. They force artificial clarity when the reality is murky. The rebuttal to this is provided by another post from Alexis King: https://lexi-lambda.github.io/blog/2020/01/19/no-dynamic-typ... > This story sounds compelling, but it isn’t true. The flaw is in the premise: static types are not about “classifying th…

In this case, the interview problem was a simplified version of a thing the team gets asked to do. So I believe it was as representative as possible for an hour's coding. I disagree that "real production code" is not throwaway. In situations of high requirements volatility, a great deal of production code ends up getting thrown away, because either a) it's intended to be a short-lived way to learn about the domain, o…

> In this case, the interview problem was a simplified version of a thing the team gets asked to do. So I believe it was as representative as possible for an hour's coding.

That's exactly my point–code written under pressure during an hour-long code challenge will never be representative of code written during normal day-to-day coding. Even if the problem domain is similar to a real-world problem.

> I disagree that "real production code" is not throwaway. In situations of high requirements volatility, a great deal of production code ends up getting thrown away

But it's not written to be thrown away an hour later. That's not really the kind of 'production code' that any reasonable person would be talking about in this thread. If you're talking about exploratory data analysis, data science or whatever, sure, you can consider it 'production code', but it's not the product of the craft of software engineering, it's more about running quick experiments.

> I'm not sold that the more elaborate approach of being thoughtfully and explicitly untyped for a project's early stages for the sake of prototyping in a statically typed language would yield much practical gain.

There are many different kinds of projects. And people who work with good statically typed languages can prototype quite well using types to drive their domain modelling. It's a different way of working. You should read some of what Scott Wlaschin has written to get an idea.

Re: Parse, Don't Validate (2019)

#277
post #269
post #268

Earlier quoted context omitted.

I don't think this analogy quite holds together. A router doing lookups from a table is implementing a static routing strategy from a control plane perspective; it's using statically configured values instead of using dynamic information about the network topology gleaned using a routing protocol like BGP. But an implementation of that strategy in terms of table lookups is dynamic—it's walking a data structure to ret…

>But an implementation of that strategy in terms of table lookups is dynamic—it's walking a data structure to retrieve values which were specified in the runtime configuration, not at compile time. That's precisely the point. You can specify part of the routing table at compile/configure time - the rest gets generated at runtime. The data/control plane distinction is conceptual. It doesn't hold in memory when the rou…

I mean, there's ample evidence on this thread to suggest we're not going to reach a productive conclusion here but I guess I'll keep biting.

It's not clear to me if you are suggesting that a dynamic routing table with different kinds of routes cannot be implemented in a type-safe manner in a statically typed language, or if you're working with an analogy where a routing table is like a dynamic programming language at runtime, in that a static set of entities and relations are known ahead of time and those are modified by runtime input. If it's the latter I'm not really sure how the analogy works—if programming languages are to routers as types are to routing entries, what in a router is analogous to a value of a given type?

I can speak more to the former possibility; here's a rough sketch of how one could implement a routing table using the tools available in a statically typed environment (and in a type-safe way). One way to do it (I believe the common way, and certainly the only one I've seen in commercial router implementations) is to treat statically populated and dynamically learned routes more or less uniformly in the data structures used to perform data-plane lookups. Each such route entry has the same fields and gets inserted into a data structure with a predefined shape. Where special behavior is needed for routes of different kinds, that behavior can be implemented by using dynamic dispatch in the sense it's usually used in C++, Java, Rust, etc. to call a method associated with a route entry, or using other techniques common to statically compiled languages—there is a fixed set of such operations defined up front. Adding and removing entries from the routing table at runtime does not typically implicate type safety because the types used to describe the table describe all of its possible valid states. For instance, the type for a node in a radix trie might describe how it can either be leaf node or contain subnodes, etc.

> The schema need not change. The entries/relations between objects changing is sufficient to violate type-safety. > > Route add( str1, str2) to Number.add().

It's obviously not always true that entries or relations changing will validate type safety; any non-trivial system will let you perform some kinds of data manipulation at runtime. Conventional static type systems will allow some kinds of mutations (like changing around pointers in a radix trie to insert a new node) but will not have the flexibility to support some others (like changing the shape of a dispatch table at runtime).

One kind of call pattern which is incompatible with statically compiled dynamic dispatch is where the types of parameters change along with the base type which owns the dispatch table; I think this is what your add() example is getting at—you need the type of the second parameter to match the first, which you can't validate without runtime checks if you don't know what concrete implementations will be in use at runtime. In the case of a routing table I don't think this kind of polymorphism is needed though; I can't think of an instance where an operation would fundamentally require a fixed relation in the concrete types of different routes. For instance, when routes overlap you can derive a priority value for each one to decide which one to use, rather than directly implementing some kind of function whichIsBetter(a, b) which relies on knowing what concrete route kinds a and b are.

Re: Parse, Don't Validate (2019)

#278

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

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

Its weird how long its taken for languages with static typing and type systems designed for correctness (and designed well for that end) rather than princupally for convenience of compilation to be available that are generally usable (considering licensing model, features, ecosystem, etc.)

Re: Parse, Don't Validate (2019)

#279
post #277
post #269

Earlier quoted context omitted.

>But an implementation of that strategy in terms of table lookups is dynamic—it's walking a data structure to retrieve values which were specified in the runtime configuration, not at compile time. That's precisely the point. You can specify part of the routing table at compile/configure time - the rest gets generated at runtime. The data/control plane distinction is conceptual. It doesn't hold in memory when the rou…

I mean, there's ample evidence on this thread to suggest we're not going to reach a productive conclusion here but I guess I'll keep biting. It's not clear to me if you are suggesting that a dynamic routing table with different kinds of routes cannot be implemented in a type-safe manner in a statically typed language, or if you're working with an analogy where a routing table is like a dynamic programming language at…

The conclusion was my very first post really. Understand the limits of your tools; and your own limits - then make acceptable trade offs.

Programming is about explaining desires to computers. It is a complex, error-prone activity and we depend on our automated tooling to save us from ourselves.

Obviously, in theory you can build the exact same software in Assembly as you can with Java. But not in practice because the programming language is a human-computer interface and a symbiosis with useful feedback loops emerges at higher levels of abstraction.

The design choices of your language impose certain limits/discipline on your expressive power.

Some design patterns become easy to express; where others become difficult to express and your paradigm’s features become obstacles.

At which point it is your choice to switch off the guard rails.

Like the chap somewhere down below telling me he will use Rust “unsafe” so he can have direct control of his memory. Yes! You can! You can also read/write to /dev/mem directly!

Translated in English “I will turn off the compiler’s safety checks because it is getting in my way”. There are many ways to shoot yourself in the foot with this level of power.

He is agreeing with me, but this is HN and opposition must be maintained. Dung must be flung. For reasons.

Sure, for certain kinds of protocols this kind of polymorphism is not always needed. But I am merely pointing out the threshold where the type-safe paradigm begins to falter. The corner cases where the pros don’t outweigh the cons. Where the “compile time” and “runtime” distinction becomes a hindrance rather than a useful separation of concerns.

You can go further. Software Defined Networks. Application router.

In general, contexts in which it would be useful to know the shape of your data at runtime!

As a spontaneous aside… if your entire information-processing system is well-typed (top to bottom) - congratulations. You are well on your way to understanding Category Theory.

The entire data-schema of your stack is what Mathemaricians call a (small) “Category”.

Re: Parse, Don't Validate (2019)

#280

Earlier quoted context omitted.

In this case, the interview problem was a simplified version of a thing the team gets asked to do. So I believe it was as representative as possible for an hour's coding. I disagree that "real production code" is not throwaway. In situations of high requirements volatility, a great deal of production code ends up getting thrown away, because either a) it's intended to be a short-lived way to learn about the domain, o…

> In this case, the interview problem was a simplified version of a thing the team gets asked to do. So I believe it was as representative as possible for an hour's coding. That's exactly my point–code written under pressure during an hour-long code challenge will never be representative of code written during normal day-to-day coding. Even if the problem domain is similar to a real-world problem. > I disagree that "…

> but it's not the product of the craft of software engineering

Sure? This seems pretty no-true-Scotsman to me. If you want to define some the things I need to do as not real software, feel free. But they're still things my team has to get done. To me there's a spectrum of domain stability on which the code rests. It's frequently not possible to know in advance which bits will be long lived and which won't be. So whether or not one of htose bits is the true "craft of software engineering" in somebody's eyes has very little interest to me. Especially when it's an anonymous rando.

> people who work with good statically typed languages can prototype quite well using types to drive their domain modelling.

I can certainly believe that's possible. Hopefully some of them will interview with me so I can see how they work. I'm just reporting the data I have.

> that's not really the kind of 'production code' that any reasonable person

In startup contexts I will quite often try an experiment that is quick to build. A few hours is not at all uncommon. That you consider me unreasonable is a sign I can better spend my time elsewhere.

Post reply on HN