HN user

eyelidlessness

12,249 karma

https://eyelidlessness.github.io/

Posts0
Comments5,723
View on HN
No posts found.

I worked on a project a couple years back that would have benefited greatly from this approach. I look forward to giving it a spin when I have an opportunity.

I’m curious how much is React-specific, or rendering-specific for that matter. Context: the use case I had previously was “headless”, in the sense that state lifecycle was completely decoupled from rendering (with a thin library-agnostic bridge for presentation layer integration). Obviously that’s not a typical use case, I’m mainly curious because that design was partly driven by the kinds of inherent complexity that would nudge me to look for something like this in the first place.

I’m surprised to see this using a `--require` hook (rather than `--import`). Maybe something’s changed significantly since I was looking into building some similar functionality… but it makes me wonder about nuances in nub’s ESM support.

(When I was investigating this it was very early in Node’s `--import` story, but there were several edge cases with the more common ESM-to-CJS approaches that I wanted to address. Most were probably exceedingly niche concerns, but I’d expect top-level await to affect a meaningful subset of users.)

I hate compilers 1 month ago

A trivial counter example to the intuition one might have that compilers likely produce deterministic output. It’s directly responsive to the exchange between Aoi and Numa above, wherein Aoi expresses exactly that intuition. Of course, those are characters playing out a question less familiar readers might ask. Presumably the intent is to make this content accessible to a wider audience, using an obvious example to introduce the concept without requiring much background knowledge.

I’m not sure kindness is the best framing. At least, not in terms of being nice to any particular person who might commit unwanted files by mistake.

It’s one of several tools a project can use to ensure quality, alongside eg linters and formatters. Automating those (in this case by defaulting to the expected outcome) reduces friction on basically every operation anyone might do in a project, in any context.

Through the lens of kindness, it benefits you as well as your team… and ultimately everyone else downstream, since you’re all not wasting time and cognitive load on trivially preventable mistakes.

Well before the LLM explosion I would often preface my answers with some form of praise for the question. It depends a lot on audience of course, but it’s amazing how many people tend to perceive direct answers to their questions as negative… and just as amazing how far a little strategic sycophancy goes to temper that. Even though everyone knows it’s half-sincere dead weight.

I agree. And I think this also distills down to Rob Pike’s rule 5, or something quite like it. If your design prioritizes modeling the domain’s data, shaping algorithms around that model, it’s usually trivial to determine how likely some “duplication” is operating on shared concepts, versus merely following a similar pattern. It may even help you refine the data model itself when confronted with the question.

It’s a muscle you can exercise, and doing so helps you learn what to focus on so it’ll be successful. IME a very successful approach is to focus on interfaces, especially at critical boundaries (critical for your use case first, then critical for your existing design/architecture).

Doing this often settles the design direction in a stable way early on. More than that, it often reveals a lot of the harder questions you’ll need to answer: domain constraints and usage expectations.

Putting this kind of work upfront can save an enormous amount of time and energy by precluding implementation work on the wrong things, and ruling out problematic approaches for both the problem at hand as well as a project’s longer term goals.

The point of a type system isn’t ever that you don’t have to check the things that make a value represent the type you intend to assign it. The point is to encode precisely the things that you need to be true for that assignment to succeed correctly. If everything is in fact modeled as an Option, then yes you have to check each thing for Some before accessing its value.

The type is a way to communicate (to the compiler, to other devs, to future you) that those are the expected invariants.

The check for invariants is trivial as you say. The value of types is in expressing what those invariants are in the first place.

But let’s dissect that last suggestion; suppose I do modify the type to encode that. Suddenly pretty much every field more or less just because Maybe/Optional. Once everything is Optional, you don’t really have a “type” anymore, you have a a runtime check of the type everywhere. This isn’t radically different than regular dynamic typing.

Of course it’s different. You have a type that accurately reflects your domain/data model. Doing that helps to ensure you know to implement the necessary runtime checks, correctly. It can also help you avoid implementing a lot of superfluous runtime checks for conditions you don’t expect to handle (and to treat those conditions as invariant violations instead).

Disclaimer: I’m a strong advocate for static typing.

I absolutely see the connection. One of the advantages of static typing is that it makes a lot of refactoring trivial (or much more than it would be otherwise). One of the side effects of making anything more trivial is that people will be more inclined to do it, without thinking as much about the consequences. It shouldn’t be a surprise that, absent other safeguards to discourage it, people will translate trivial refactoring into unexpected breaking changes.

Moreover, they may do this consciously, on the basis that “it was trivial for me to refactor, it should be trivial to adapt downstream.” I’ll even admit to making exactly that judgment call, in exactly those terms. Granted I’m much less cavalier about it when the breaking changes affect people I don’t interface with on a regular basis. But I’m much less cavalier about that sort of impact across the board than I’ve observed in many of my peers.

You might want that, I might too. But it’s outside the constraints set by the post/author. They want to establish immutable semantics with unmodified TypeScript, which doesn’t have any effect on the semantics of assignment or built in prototypes.

Marko’s compiler is designed for partial hydration (by default, without any special developer effort), which performs quite well. IIRC they were also looking at implementing “resumability” (term coined by Qwik, for an approach that sidesteps hydration as a concept entirely). I’m not sure where they’re at on that now, but I think it’s generally safe to say that Marko prioritizes load time performance more than nearly all other frameworks.

I don’t agree with your characterization that anyone is “pretending”. The whole point of abstraction is convenience of reasoning. No one is fooling themselves or anyone else, nor trying to. It’s a conscious choice, for clear purposes. That’s precisely as hilarious as using another abstraction you might favor more, such as an effect system.

But there isn’t anything hilarious about that.

It’s a clear-minded and deliberate approach to reconciling principle with pragmatic utility. We can debate whether it’s the best approach, but it isn’t like… logically inconsistent, surprising, or lacking in self awareness.

Sometimes they even fail to even realise that it's what they are doing.

Because that’s not what they’re doing. They’re isolating state in a systemic, predictable way.

To some extent you’ve answered this yourself: TypeScript (and/or linting) is the way to be warned about this. Aside from the points in sibling comment (also correct), adding these kinds of runtime checks would have performance implications that I don’t think could be taken lightly. But it’s not really necessary: static analysis tools designed for this are already great, you just have to use them!

This is a matter of choice, not something with an objectively correct answer. Every possible answer has trade offs. I think consistency with the underlying standard defining NaN probably has better tradeoffs in general, and more specific answers can always be built on top of that.

That said, I don’t think undefined in JS has the colloquial meaning you’re using here. The tradeoffs would be potentially much more confusing and error prone for that reason alone.

It might be more “correct” (logically; standard aside) to throw, as others suggest. But that would have considerable ergonomic tradeoffs that might make code implementing simple math incredibly hard to understand in practice.

A language with better error handling ergonomics overall might fare better though.

It’s not even safe if you’re 100% sure the types are compatible, unless you’re also 100% sure nothing will change that fact. The reason it’s unsafe is because it suppresses the type error permanently, even if whatever factors led to your certainty now change anywhere upstream ever.

There are certainly ways to guard against that, but most of them involve some amount of accepting that the type checker produces errors for a reason.

Thank you for clarifying. (I think?)

I think what confused me is the passive language: "everything gets converted" sounds (to me) like the runtime or some aspect of language semantics is converting everything, rather than developers. Whereas this is the same complaint I mentioned.

Right, but I’m not clear on what gets converted to an array. Do you mean more or less what I said in my previous comment? That it requires you (your code, or calling code in general) to perform that conversion excessively?

everything gets converted to an array at the drop of a hat

Can you name an example? IME the opposite is a more common complaint: needing to explicitly convert values to arrays from many common APIs which return eg iterables/iterators.

Context: until fairly recently, I worked an implementation of XForms (as the project creator, and leading most of the architecture/design). Prior to that, I inherited maintenance of another implementation, which utilized XSLT[1] as a core aspect of its design.

I’m curious if you could describe more about what you envision. I have a difficult time imagining:

1. How the stateful/interactive aspects of XForms (such as insert/delete, as you mention) would be implemented client side without JS.

2. How XSLT factors into that vision.

It might be lack of imagination on my part! Admittedly, I don’t know everything about XSLT and maybe it has more interactive capabilities than I’m aware of. But at least as far as I know, when a browser vendor did implement XForms functionality it still ultimately depended on JS to achieve certain behaviors. It’s been a while since I was looking into this, but IIRC it looked conceptually similar to XUL. And granted, that might mean the JS is provided by a browser, and encapsulated from user space similar to browsers’ use of shadow DOM for standard form controls now.

1: I also have good reason to believe my work on this prior project helped keep XSLT alive in Chrome the last time there was a major push to deprecate it! Albeit totally inadvertently: my work just happened to correlate very closely to a spike in usage metrics around the same time, which was then cited as a reason to hold off on deprecation.

Because HTML attributes are inherently stringly typed. Where CSS can propagate types, it’s because the CSS parser and object model are involved. For that to work with attr() would almost certainly involve extending that machinery into all aspects of the HTML spec, and then all that machinery too. Which is probably impractical for more reasons than I can think of, but I can think of several.

I read it as describing their preferred mental model for declaring a result set, which is different from describing their preferred behavior to produce it. This seems clear to me in wording and context; it’s also broadly consistent with how SQL is understood, and how it is generally implemented.

Only personal anecdata, but I’ve observed that I’m far less accident prone since I was diagnosed and have had consistent treatment. I noticed it without prompt, and it never occurred to me before that there would be any correlation.

I’ve also noticed I’m much less accident prone since I’ve been sober, which came a couple years later. I couldn’t say for certain which event correlates with a more pronounced improvement, but both have been quite pronounced.

That said, yes, I can still relate to bruised shins! I’m less accident prone, but still pretty far from immune.