tc39 / proposal-get-intrinsic

EcmaScript language proposal for a way to get intrinsics.
https://tc39.github.io/proposal-get-intrinsic/
MIT License
32 stars 4 forks source link

Some userland “prior art” (realm-uri) and what I learned from it #10

Closed bathos closed 2 years ago

bathos commented 2 years ago

A few years back I wrote a plugin for rollup (which can be used with esbuild now too), realm-uri, that may be of interest here. It implements a custom URI scheme & grammar overlaying import specifiers. The modules that are resolved are virtual/generated. Being a compilation-time solution, it has the advantage of deduplication and the disadvantages typical of compilation-time-anything.

The mechanism and grammar/DSL/API is described in its readme, but I’ll try to summarize the premise. The URI pathname has two components separated by a slash, “context” and “path”, with the first being optional. The context identifies a well-known intrinsic object which may be unreachable from globalThis. These are finite, having hardcoded names, and when omitted, globalThis is the default context. The path portion is a serialized property access chain with grammar resembling a MemberExpression. This resemblance aims to be intuitive for common cases, but is only superficial; the syntax which looks like computed access doesn’t accept arbitrary expressions and global and well-known symbol keys are indicated with unique notation.

Though the tool has very little in common with getIntrinsic in terms of specific solutions and scope, the motivating problems described here are common to both. There are portions of the realm-uri readme that wouldn’t seem out of place if plopped in the readme here and vice versa.

If the getIntrinsic proposal succeeds, it would be natural to leverage it within realm-uri to replace components concerned with the-getting-of-intrinsics. Since that accounts for a good portion of the code, realm-uri could be considered a userland prior art example that demonstrates interest in / benefits from the functionality of getIntrinsic — though nobody uses my weird lil library except me as far as I know, so I’m not suggesting it’s noteworthy in a “Prior art: lodash.yogurt()” way. However I do think I learned something from it that is worth sharing here.

When I wrote realm-uri, it was one of many solutions I experimented with and wasn’t the last. I dropped it pretty quick to see how the next attempt might pan out. I was pretty much doing something new every week and was very reluctant to have any sort of custom build step. But I kept finding myself returning to it. It gradually became “the easy one”, even “the natural one,” which I realize sounds odd given it’s a pretty idiosyncratic premise.

I think it came down to how much it lowered the cognitive load just by reducing perceived noise. A single declarative statement could express “I want some specific accessor property’s getter function and I want it receiver-as-arg”. I no longer needed to do imperative “follow up” to turn the things-I-got into something-elses before I could use them. Import & use. An API surface that addresses getters, setters, and method “inversion” (receiver-as-first-arg) in an all-in-one way was what made the usability difference. In fact, some of the code I write using realm-uri borders on readable :)

It would be pretty sweet if a runtime API could provide that sort of Almost Ergonomic™ experience. Is this something that’s been considered? Is it in scope? Would it be in scope for follow-on proposals?

ljharb commented 2 years ago

I think the “receiver-in-arg” piece would be covered by the bind-this proposal, in concert with this one. I don’t think there’s any viability with “import something ready-to-use”, even if only because that wouldn’t solve anything for Scripts, which must always be considered on equal footing as Modules.

I intentionally avoided making a proposal whose scope was that large. I think it’s more viable to solve it piecemeal, since i think each piece is independently motivated, rather than trying to solve a large problem all at once.

bathos commented 2 years ago

I think the “receiver-in-arg” piece would be covered by the bind-this proposal, in concert with this one.

Good point, that would be sweet.

I don’t think there’s any viability with “import something ready-to-use”

Totally agreed. I didn’t meant to suggest that I think the model used by that library is realistic for a formal solution. I would prefer a runtime solution.

I think it’s more viable to solve it piecemeal, since i think each piece is independently motivated, rather than trying to solve a large problem all at once.

That is intuitive to me. My “finding” (which surprised me) was essentially that the DSL had disproportionately high value (and more unintuitively still: that its “density” was a critical part of that). My hope is not that it be solved all at once, just that whatever components come out of this will have a “crisp fit” that could achieve the kinds of keep-the-noise-in-the-noise-hole characteristics that I found valuable.

ljharb commented 2 years ago

I completely agree that having the final use case (which is mine also) be ergonomic will be of high value.

I'm also confident that each independently-motivated piece can advance, taking that into account, so that goal can be reached without needing to convince the entire committee of the value of the overarching goal.

Given that, I'll close this as out of scope - but thanks for the use case, and I'm more than happy to keep discussing things.

js-choi commented 2 years ago

I think the “receiver-in-arg” piece would be covered by the bind-this proposal, in concert with this one.

(For anyone else following along, the bind-this operator is currently at Stage 1.)