01:42
<littledan>
* some people are coming into the AsyncContext group and proposing other semantics which would permit more like this scheduler.yield pattern. I've generally been pushing back on it.
10:38
<Andreu Botella>
Hey, turns out scheduler.yield does not actually behave in the way we explained yesterday – I had a bad misunderstanding based on looking at that API only in a narrow context related to the AsyncContext web integration, and not looking at how it's actually used
10:40
<Andreu Botella>
there is no enterWith, and the API semantics are expressible with AsyncContext – but there's still a "shared global state" that can be observed
10:42
<littledan>
* some people are coming into the AsyncContext group and proposing other semantics which would permit more like this scheduler.yield pattern (EDIT: I had misunderstood scheduler.yield semantics, Andreu clarifies below). I've generally been pushing back on it.
10:46
<Andreu Botella>
const controller = new AbortController();
scheduler.postTask(async () => {
  try {
    // this "inherits" the signal set by postTask, and if it
    // gets aborted before the task is scheduled, the promise rejects
    await scheduler.yield();
  } catch(err) {
    console.log("Signal was aborted!");
  }
}, {signal: controller.signal})
11:05
<nicolo-ribaudo>

So this is equivalent to doing the following with AsyncContext?

globalThis.scheduler = new class Scheduler {
  #signals = new AsyncContext.Variable();

  postTask(fn, { signal }) {
    this.#signals.run(signal, fn);
  }

  async yield() {
    const signal = this.#signals.get();
    while (shouldWaitABitMore()) {
      await yieldToTheEventLopo();
      if (signal.aborted) throw new Error("Abort");
    }
  }
};
11:06
<nicolo-ribaudo>
i.e. the problem is not related to AsyncContext itself, but to the globalThis.scheduler = assignment
11:11
<Andreu Botella>
that's right
17:54
<snek>
this seems like a pretty reasonable usage of async context, why is the word "problem" used?
18:03
<Ashley Claymore>
Two different bits of code that only share a reference to β€˜globalThis.scheduler` can communicate information to each other. (Even after scheduler itself is frozen)
18:05
<littledan>
this seems like a pretty reasonable usage of async context, why is the word "problem" used?
Because Mathieu Hofman previously said that this kind of thing might form a communication channel, so we were trying to figure out whether this was a problem (he seemed to be saying it was, but I'm having trouble understanding how/why)
18:06
<snek>
oh its an ses problem ok
18:07
<Ashley Claymore>
The ses recordings of the analysis of async context are really interesting 
18:10
<snek>
i wish all the human effort that went into ses went into a good realms api instead
20:43
<Stephen Belanger>
Because Mathieu Hofman previously said that this kind of thing might form a communication channel, so we were trying to figure out whether this was a problem (he seemed to be saying it was, but I'm having trouble understanding how/why)
Forming a communication channel is kind of the point of async context management. It's a transport of values between two otherwise disconnected points. However, it's mediated through a storage variable and so should not be considered "insecure" as access to the store itself functions as the "key" to access that data.
20:46
<Stephen Belanger>
Context management is a mechanism of flowing data alongside execution without explicit argument passing but rather through a store mediator to essentially handle that flowing itself. Access is still explicit, just rather than passing something in as a function argument you're passing it into a store to serve as a channel to the later point at which the value would be acquired.
21:02
<Mathieu Hofman>
It's an everybody problem. Observable global mutable state is hard to reason about. It's spooky action at a distance. An app can do it, but libraries and runtimes shouldn't
21:04
<Mathieu Hofman>
Are we really debating whether observable global mutable state is a good idea or not in a language?
21:08
<Andreu Botella>
it's observable only within a limited scope, and (presumably, although this will have to be discussed for every such API) overridable with AsyncContext.Snapshot so nothing can be observed within an inner scope
21:12
<Stephen Belanger>
Async context isn't global though, it's store-bound. It just happens to need global facilities to manage the propagation, but the same could be said of connecting lexical scopes. 🀷
21:13
<bakkot>
scheduler is global
21:14
<Stephen Belanger>
Ah, I don't have the full context on the scheduler part of the conversation, but async context on its own is certainly not global. Definitely agreed global state is not great.
21:15
<Stephen Belanger>
I just joined this channel after some folks mentioned AsyncContext discussions were happening here too, so I'm a bit behind on the conversation. πŸ˜…
21:18
<Stephen Belanger>
I'm the maintainer of AsyncLocalStorage in Node.js, btw. πŸ‘‹
21:19
<Andreu Botella>
Are we really debating whether observable global mutable state is a good idea or not in a language?
Whether or not it's a good idea, there are use cases (in the web platform) that apparently can't be solved without some kind of observable global mutation. If you're arguing that HTML shouldn't use global mutable state, you're arguing that the web platform should stop existing because the DOM is globally mutable, and that can't change because it's part of web reality
21:26
<ljharb>
that's not the same thing. arguing that HTML "should have" been designed differently is not an argument that it should stop existing.
21:27
<ljharb>
in practice it's a huge mess that the DOM is globally mutable.
21:27
<ljharb>
that doesn't mean a better alternative currently exists, nor that the DOM should be summarily scrapped
21:29
<Ashley Claymore>
Ah, I don't have the full context on the scheduler part of the conversation, but async context on its own is certainly not global. Definitely agreed global state is not great.
There is a 4 part series of ses analyzing AsyncContext on YouTube. The final conclusion is that it's OK πŸ˜€
21:29
<Ashley Claymore>
Also πŸ‘‹πŸ» welcome!
21:29
<Stephen Belanger>
Okay in the state it is today...which has some problems for tracing purposes. πŸ˜…
21:30
<Stephen Belanger>
But that's a whole can of worms I've already opened in the AsyncContext channel.
21:34
<Stephen Belanger>
Would you happen to have the link to those videos though? I've seen what I presume is the corresponding github repo where some analysis happened, but could use more context on exactly what their analysis was of the model. Context management has basically been my entire job for half a decade now, so I have a whole lot of...context...in my head about the problem. πŸ˜…
21:35
<Stephen Belanger>
Ah, is this the first? https://www.youtube.com/watch?v=vECr5IDJzpg
21:36
<Mathieu Hofman>
The Web has indeed a few design flaws. What seems unfortunate is that it seems acceptable to justify the addition of similar flaws just because of these historical ones. JS on its own however does not have any problems of observable internal mutable state today. "internal" is specifically there to address the fact that the global properties and other language intrinsics are not frozen.
21:41
<Andreu Botella>
The W3C has a concept called priority of constituencies, used for designing APIs and determining how to solve problems, and it puts the needs of users (of the web) at the top, followed by the needs of authors (i.e. web developers)... with ideological purity being at the bottom. And I see the principle of avoiding observable global mutable state as an ideological purity concern, way below the use cases authors might have.
21:41
<Andreu Botella>
That said, I can see how global mutable state can affect authors. But then we'd have to see how a particular API that adds global mutable state might make things harder for authors, and whether it might outweigh the needs for the API itself. For scheduler.yield, that is a discussion I don't have enough context for, but IMO it'd have to be discussed in those terms, not in terms of ideological purity.
21:45
<bakkot>

And I see the principle of avoiding observable global mutable state as an ideological purity concern, way below the use cases authors might have.

I think this attitude from web platform people is part of the reason that so much of the web is such a painful experience. it's not an ideological purity concern. it's a reasoning about code concern: the point is that it makes it easier to avoid bugs, which is directly to the benefit of users.

21:47
<bakkot>
now, in any particular case it may or may not be warranted, depending on the details. but when discussing API design, dismissing "code should be easy to reason about" as being at the bottom of the priority of constituencies does real and direct harm to users. people should stop that.
21:52
<Andreu Botella>
Anyway, I'm not trying to defend how scheduler.yield works, I'm just trying to see how/if the behavior it has (at least in Chrome behind a flag) could be specable and implementable based on AsyncContext, because if it's not, V8's odds of okaying AsyncContext might drop significantly
23:11
<snek>
maybe i misunderstood the concern. how would access to the ambient runtime scheduler not be a global
23:13
<snek>
oh that was meant to be a reply... Mathieu Hofman
23:28
<Mathieu Hofman>
this is a loaded question. Pushing a task on a scheduling queue does not allow independent tasks to observe each other. After all we allow that at a lower level through Promise.prototype.then. So there is global mutable state (the scheduling queue), but it's not observable. The problem is with making some of that state observable. An obvious case would be letting user code ask the question "is there anything remaining on the global queue?". But there are more subtle cases: letting the spawner of the task ambiently communicate with the running task is effectively global mutable state being observed too. One way to make that explicit would be to require a shared reference between the spawner and the task, for example an instance of Scheduler, or simply letting the code plumb the abort signal on its own through an AsyncContext variable it creates. The latter would actually let it retrieve the signal and propagate it to other API calls such as fetch.
23:33
<snek>
hmm. all web code is kind of within a shared goal though i think... like there's a webpage with a viewport, and the browser wants to render it effectively, and all the code for the webpage presumably also wants the page to be rendered effectively. if you require all code to explicitly pass this info around, its less effective. and if you imagine every bit of code 100% proactively updated to support an explicit scheduler argument, isn't that just equiv to a global?
23:35
<snek>
well, if you're trying to defend against malevolent code, i can understand how its not equiv to a global. but the discussion above didn't seem like it was about that, but rather avoiding bugs.