13:07 | <Stephen Belanger> | Here's a new issue from Matteo about the exact issue I'm talking about with await binding. I've seen this user confusion come up a lot. https://github.com/nodejs/node/issues/53037 |
13:08 | <Stephen Belanger> | It happens to use enterWith(...) rather than run(...) , but the confusion around expected flow is effectively the same. |
13:26 | <Stephen Belanger> | Do you have an example of this sort of fix, and the costs and benefits of it, that we can look into? store.get() and store.run(...) in a closure, but then you're making a closure and doing some extra steps which could probably be more optimizable as an instance-scoped bind method of some sort. |
13:28 | <Stephen Belanger> | Catching up on a lot here. I think I'm starting to come around a bit more to Stephen's perspective w.r.t. context flowing out from resolves. I think he's right that, in general (when people do the right thing) it ends up maintaining the same root for the context tree, since the resolved promise generally comes from earlier in the same scope, and I like the fact that it aligns the opt-in for registration time with something that's actually quite reasonable to implement. I believe it's also pretty trivial to do a paranoid await-wrapping: `await bindTask(() => untrustedApi())` which would guarantee the untrustedApi can't change the context on you. Where it still feels wrong to me is Andreu's concern. The really nice property in the current proposal is that it's really well encapsulated. Context variable behave just like lexical consts, where you have guarantees that anything you can't see can never change them out from under you, and that's a _very attractive_ guarantee. Whereas the flows-out approach seems very brittle if any single bad/careless actor anywhere in your downstream call chain is able to irretrievably break the flow. I think that's where this disconnect is coming from - the encapsulation purists in the group are very hesitant to give up that guarantee. |
13:33 | <Stephen Belanger> | Also, the using syntax doesn't play particularly nice with async context as it not only crosses over async barriers, but also (as far as I'm aware) does nothing to signal any sort of change of state around awaits in its scope so if you, for example, mutate a global in whatever the using is doing and then expect it to restore the value when the use expires it may also be required that the value is altered to match the appropriate value between async code, so I expect that is going to be a bit of a footgun when combined with async code. |
13:36 | <Stephen Belanger> | If you are coming around to this point, do you have ideas about answers to the questions I was asking? Namely, what do we hope to get from merge points, which happen all the time? |
13:47 | <Stephen Belanger> |
|
14:10 | <Stephen Belanger> | Also, I'd really appreciate if people reconsidered much of what James M Snell was was saying in https://github.com/nodejs/node/issues/46262. As far as people that understand the issues of context flow, he's one of very few others I'd trust to understand this stuff, having done a bunch of work on the Cloudflare equivalent of AsyncLocalStorage. |