00:00
<bakkot>
re: waldemar's point, I agree that more general async dataflow would be great, and is something we should explore, though I think I'd still want this proposal for simple case
00:02
<justinfagnani>
re: Mark's comments now... when you see a ton of code that's accidentally serial instead of parallel, you really wish for a better syntax for all of this that doesn't encourage bad behavior
00:06
<HE Shi-Jun>
re: waldemar's point, I agree that more general async dataflow would be great, and is something we should explore, though I think I'd still want this proposal for simple case
but it seems not have big benefit for simple case :)
00:09
<rbuckton>
I'm fairly certain a cover grammar is feasible for await using, the big question is whether what I have put together is correct. Given the NLT restrictions, an await using declaration must have the first identifier in the binding list on the same line as await using, and that is always a syntax error in the expression case. Binding patterns aren't permitted in using, so there is no ambiguity with await using [x].
00:10
<shu>
i'm gonna level with you rbuckton, i do not have enough brainpower left today to vet that cover grammar
00:10
<shu>
though i'm more interested in how hard it is to implement in a recursive-descent parser anyhow
00:10
<shu>
i'll try to put time aside before plenary tomorrow to look, but... i also have a presentation tomorrow first thing so also no promises
00:14
<rbuckton>
The gist of it is, the cover is identical to AwaitExpression, but UnaryExpression would fail to parse await using x when x is on the same line. AwaitUsingDeclaration however would be able to consume the cover along with a trailing [no LineTerminator here] BindingList, which seems pretty much equivalent to CoverParenthesizedExpressionAndArrowParameterList and CoverCallExpressionAndAsyncArrowHead
00:16
<shu>
that... sounds reasonable
00:16
<rbuckton>
Though I'll admit, cover grammars in the spec today sometimes seem a bit hand-wavy in a couple places.
00:16
<shu>
and i just do a bounded look ahead await using and see if it's an NLTH identifier
00:17
<shu>
in +Await contexts
00:17
<rbuckton>
In TS I'd just do two-token lookahead in +Await
00:17
<rbuckton>
That is one benefit of await using over async using. For await using, both uses of the cover are in +Await, while for async using, only one is.
00:18
<shu>
and await using without a binding list is unaffected?
00:19
<shu>
well, is supposed to be, according to the cover
00:19
<rbuckton>
In TS I'd just do two-token lookahead in +Await
In fact, I've already done that in my current work on using (I was experimenting with all three syntax options).
00:20
<shu>
is TS a hand-written recursive-descent?
00:22
<rbuckton>
and await using without a binding list is unaffected?
I'm not sure what you mean by this. await using on its own, or anywhere else legal for a UnaryExpression, should end up treated as an AwaitExpression.
00:22
<shu>
yes, that is what i meant
00:25
<rbuckton>
From my understanding of cover grammars, we would eagerly parse CoverAwaitExpressionAndAwaitUsingDeclarationHead, but fail to parse the rest of ExpressionStatement. We could then retry the parse as part of AwaitUsingDeclaration, reusing the cover, and be able to successfully continue to parse. Then static semantics kick in and validate that the CoverAwaitExpressionAndAwaitUsingDeclarationHead is a valid AwaitUsingDeclarationHead (e.g., await [NLT] using)
00:25
<shu>
i am happy enough to go forward with stage 3
00:27
<rbuckton>
I will amend the slides with a summary of these changes and wait to see if Waldemar is able to provide feedback in the meantime.
02:53
<Michael Ficarra>
is there anything we need to do to get Decimal on the overflow, or will it be taken care of?
03:09
<littledan>
is there anything we need to do to get Decimal on the overflow, or will it be taken care of?
If there is time to go through the queue for decimal, that would be great, but we could also do that next meeting
03:10
<Michael Ficarra>
of course, I just wanted to record it on the list of overflow items
06:15
<bakkot>
ljharb: I made some slides just for mark, if we have time tomorrow, PTAL: https://docs.google.com/presentation/d/1s1IZSo24JpMsI_NponP8vvIKUazld62lcleKF976Ppc/edit?usp=sharing
14:01
<Richard Gibson>
ljharb: I made some slides just for mark, if we have time tomorrow, PTAL: https://docs.google.com/presentation/d/1s1IZSo24JpMsI_NponP8vvIKUazld62lcleKF976Ppc/edit?usp=sharing
note the changes would need to be more substantive for dealing with v-mode, which has a wider set of reserved punctuators and semantics for doubled punctuators (https://github.com/tc39/proposal-regexp-v-flag#how-is-the-v-flag-different-from-the-u-flag and https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2418#prod-ClassSetCharacter )
14:42
<rbuckton>
Are we ensuring that RegExp.escape is future proof against potential new syntax? Should we be concerned if the output changes in a later version if we have to escape something new? We could choose to be intentionally over-aggressive with escapes, if we're not already.
14:53
<rbuckton>
Also, rather than extending u-mode to allow other escapes, we could escape non-u-mode syntax characters using a hexadecimal representation that is legal in all modes. So, instead of adding \-, we could choose to escape it as \x2d. Same for \= (\x3d) and \, (\x2c)
14:53
<rbuckton>
I'm not saying we shouldn't extend u-mode, but this is an option if we decide not to.
15:12
<rbuckton>

Regarding the "exhaustive list of contexts", keep in mind that several proposals add other contexts:

  • Modifiers: (?imsx-imsx:...) (stage 3)
  • Comments: (?#...) (stage 1)
  • x-mode line comments: # ... (stage 1)
  • Atomic Groups: (?>...) (stage 1)
  • Conditionals: (?(...)...|...) (stage 0, though I'm still hoping we'll take it eventually)

At a quick glance, I think this means that # may need to be escaped as well, lest it be misinterpreted in x mode.

15:14
<rbuckton>
If there's a chance we want RegExp.escape to always remain stable, it may be worth going over the RegExp syntax investigation I did at https://rbuckton.github.io/regexp-features/features/ to ensure we're future-proof against other syntax we may choose to adopt later. Though, I admit that's not a completely exhaustive list.
15:15
<Chris de Almeida>
I've just had to reference the notes as I had to leave early yesterday, and the conclusion/summary for each agenda item was a nice help
15:23
<Jesse (TC39)>
how does scheduling of overflow stuff happen? asking for a friend
15:24
<bakkot>
note the changes would need to be more substantive for dealing with v-mode, which has a wider set of reserved punctuators and semantics for doubled punctuators (https://github.com/tc39/proposal-regexp-v-flag#how-is-the-v-flag-different-from-the-u-flag and https://arai-a.github.io/ecma262-compare/snapshot.html?pr=2418#prod-ClassSetCharacter )
The changes are just a matter of including the punctuators which have meaning (or are reserved) in v-mode; the doubled punctuators don't actually end up mattering as long as the non-doubled versions are all escaped
15:25
<bakkot>
the list of reserved punctuators already includes #, so it would be escaped also, which would cover x-mode line comments too, thankfully
15:26
<rbuckton>
If there's a chance we want RegExp.escape to always remain stable, it may be worth going over the RegExp syntax investigation I did at https://rbuckton.github.io/regexp-features/features/ to ensure we're future-proof against other syntax we may choose to adopt later. Though, I admit that's not a completely exhaustive list.
For example, we may never do recursive matching, but it still might be a good idea to escape & (used in (?&name) for recursive named capture group matching, and (?(R&name)A|B) in conditionals to test for recursion of a group).
15:26
<bakkot>
For example, we may never do recursive matching, but it still might be a good idea to escape & (used in (?&name) for recursive named capture group matching, and (?(R&name)A|B) in conditionals to test for recursion of a group).
& needs to be escaped anyway for v-mode
15:26
<rbuckton>
the list of reserved punctuators already includes #, so it would be escaped also, which would cover x-mode line comments too, thankfully
That's not shown in the slides though, which only mentions (){}[]|,.?*+-^$=<>\
15:26
<bakkot>
it does say "etc"
15:27
<Chris de Almeida>
pull request to the agenda
15:27
<Rob Palmer>
The best way is to PR the agenda as that guarantees all chairs will see it. But normally messaging the chairs in matrix is enough. I will say that after we add Ron's overflow, there is not much chance of more overflow.
15:27
<rbuckton>
Yeah, but that's somewhat unclear. If it were to escape A, for example, that would be a problem for https://github.com/tc39/proposal-regexp-buffer-boundaries
15:28
<Chris de Almeida>
there's already o-f for async ex res mgmt - 30 mins. is there an additional item from Ron?
15:29
<bakkot>
It does also say it's only including punctuators, which would not include A
15:29
<Chris de Almeida>
oh... there was only a spare 25 minutes in the schedule to begin with
15:30
<rbuckton>
Plus that list doesn't match the explainer currently, so there doesn't seem to be a definitive source of truth. Maybe that's a stage 2 concern, but if the point of the slides is "RegExp.escape is safe", then its important to clarify how safe.
15:44
<eemeli>
Presumably it's sufficient to guarantee that RegExp.escape() safe for its own RegExp, rather than being safe forever.
15:45
<bakkot>
Well, that depends on whether anyone starts depending on it not escaping certain things
15:51
<bakkot>
rbuckton: Updated the slides to list proposed contexts as well, and went through all the ones you listed in your research doc as well
15:51
<bakkot>
I'm kinda tempted to just say it escapes every ascii punctuator except _, since I've listed I think all of them except the two quotes and backtick at this point
15:51
<bakkot>
I did also update it to include line terminators so you can't break out of x-mode line comments, which is something I'd previously neglected
15:53
<rbuckton>
That's why I posed the questions earlier. Do we need to ensure RegExp.escape() is consistent for all time? If so, do we do that my making a best guess as to what potential syntax characters we might encounter in the future, and will that limit us in terms of what new syntax we can add? Or do we aggressively escape anything that is not alpha-numeric (or equivalent unicode characters)?
15:54
<rbuckton>
I'm kinda tempted to just say it escapes every ascii punctuator except _, since I've listed I think all of them except the two quotes and backtick at this point
I think that may be safer, though _ might even be worth escaping since it has meaning as part of some control verbs in Perl.
15:54
<bakkot>
I think we should commit to not using _ for anything ever
15:54
<bakkot>
v-mode had that discussion already when they decided not to include it in the double-punctuator reservations
15:55
<rbuckton>
Perl has (*positive_lookahead: ... ), for example
15:56
<bakkot>
ah, that seems more like it's being used as an identifier character, and doesn't need to be escaped any more than any other identifier character
15:57
<rbuckton>
PCRE also uses `, ', ", and % for callouts.
15:57
<rbuckton>
I'm not sure we'll ever do callouts, but you can never be certain.
15:57
<bakkot>
ok I will just say every ascii punctuator
15:57
<bakkot>
except _
15:58
<bakkot>
And note that we might be able to make it less aggressive
15:58
<rbuckton>
That's fine with me.
15:59
<bakkot>
re: future constraints, this does mean that we're committing that backslash + punctuator is only ever going to mean the punctuator, but that is I think a good limit to impose
15:59
<rbuckton>
PCRE also uses `, ', ", and % for callouts.
' is actually used quite a bit across RegExp engines, primarily as an alternative to <> for named capture groups.
16:03
<rbuckton>
re: future constraints, this does mean that we're committing that backslash + punctuator is only ever going to mean the punctuator, but that is I think a good limit to impose
As far as I can tell, no. The most likely engines that might have that would be Perl, PCRE, and Oniguruma, but I don't see anything like that so far.
16:04
<bakkot>
Sorry, by "no" do you mean "no one uses backslash + punctuator to mean anything other than the punctuator"?
16:04
<rbuckton>
Sorry, by "no" do you mean "no one uses backslash + punctuator to mean anything other than the punctuator"?
Correct, though I'm still checking.
16:05
<rbuckton>
I think it would be safe to say that we also would never consider \+punctuator to mean anything other than the punctuator.
16:06
<rbuckton>
There are other ways to introduce syntax that would be more meaningful than, say, whatever \~ might mean.
16:56
<shu>
chairs, am i still up first today? if so i'll be about 2-3 mins late
16:57
<Chris de Almeida>
chairs, am i still up first today? if so i'll be about 2-3 mins late
yes - Shared structs update
16:57
<shu>
thanks for confirmation
16:58
<shu>
(reason being i still don't have home internet and have to wait till 10 to kick people out of the meeting room i booked)
16:59
<Chris de Almeida>
should be fine -- room still fairly empty over there
17:05
<Willian Martins>
I love this deck.
17:06
<Andreu Botella>
wait, at what stage is shared structs?
17:06
<HE Shi-Jun>
Is that only me can't see shared screen?
17:06
<Andreu Botella>
I can see it
17:07
<Chris de Almeida>
maybe you have something else pinned?
17:07
<Chris de Almeida>
in top left, is there a button to switch to shared content?
17:08
<HE Shi-Jun>
exit and rejoin, still can't see shared screen 😭
17:09
<Chris de Almeida>
using app or browser?
17:09
<ryzokuken>
wait, at what stage is shared structs?
1: https://github.com/tc39/proposal-structs
17:09
<HE Shi-Jun>
app
17:10
<Andreu Botella>
oh, I was Ctrl+Fing for "shared" in the proposal lists and couldn't find it
17:10
<HE Shi-Jun>
it works now!
17:10
<ryzokuken>
well, ideally that'd imply Stage 0 🙈
17:10
<Chris de Almeida>
it's missing from the proposals repo...
17:10
<littledan>
"Shared structs" have always been part of Shu's "structs" proposal.
17:10
<HE Shi-Jun>
ok, i can see the screen now. not sure what happened , may be just network issue.
17:11
<ljharb>
stage 1 (and zero) proposals are in a separate list
17:11
<Chris de Almeida>
yeah it;s still missing from the list
17:12
<Chris de Almeida>
https://github.com/tc39/proposals/blob/main/stage-1-proposals.md
17:12
<Andreu Botella>
yeah, I was searching in all lists, but I was searching for "shared" and couldn't find it
17:12
<ljharb>
"fixed shape objects" is in the list
17:12
<ljharb>
that was what it was presented as when it got stage 1, i assume
17:12
<Chris de Almeida>
ohhhh
17:12
<Chris de Almeida>
quick PR incoming
17:13
<ljharb>
Chris de Almeida: i'm not sure that's appropriate
17:13
<Andreu Botella>
Maybe this is just me, but the name "isolate" shouldn't necessarily guide the direction of the language /s
17:13
<ljharb>
at stage 1 the proposal name should describe the problem, and "shared structs" seems like a solution to me
17:14
<littledan>
Maybe this is just me, but the name "isolate" shouldn't necessarily guide the direction of the language /s
heh I guess this is more generally intelligible if you replace "isolate" with "garbage collected heap"
17:15
<littledan>
at stage 1 the proposal name should describe the problem, and "shared structs" seems like a solution to me
I think we can afford champions some flexibility here, but Shu is clearly referring to this proposal as "shared structs" so it's fine to go with that.
17:15
<ljharb>
fair enough
17:17
<Chris de Almeida>
I think it's reasonable to expect better parity between the title in the tc39/proposals repo and the title on the proposal repo itself
17:17
<littledan>
Note: I believe Shu is using the term "closed" in a mathematical sense, about how these graphs don't point to each other.
17:18
<littledan>
and "mutators" refers to the executing code (which mutates the heap--even if it's purely functional)
17:27
<ljharb>
i usually default to whatever's on the agenda at advancement time in the proposals table
17:27
<ljharb>
but i agree that it would be nice if champions kept that in sync :-)
17:48
<Luca Casonato>
shu: The origin isolation is not really an issue for us in Deno, because our security model ensures that only a single tenant can execute code within a single process. Essentially the effect of cross origin isolation is the default for us. There are some server side runtimes, notably Cloudflare Workers, that run multiple tenants within a single process. They disallow all high precision timers and shared memory entirely.
17:52
<Andreu Botella>
can't you treat a reference to a SAB from inside a shared struct as if it was a per-isolate SAB object
17:52
<Andreu Botella>
different from any other SAB object pointing to the same backing store in the same isolate
17:56
<Luca Casonato>
Technically probably possible - the identity continuity seems pretty hard (but probably possible). I think the biggest problem is wether this should work, because magic object cloning is not something we have right now. Also what if you have a custom class that extends SAB?
17:57
<Andreu Botella>
Is there a need for identity continuity? You can currently clone a SAB without identity continuity with HTML's structuredClone(sab)
17:57
<Andreu Botella>
But I guess it would be needed for some use cases
17:58
<Luca Casonato>
Yes, but there you have an explicit transfer
17:58
<Andreu Botella>
Oh, right, this would be an assignment transforming into a clone behind the scenes
17:58
<Luca Casonato>
With shared structs, assignment is transfer/publish, which means there is no explicit call that needs to be made to transfer
17:59
<Luca Casonato>
sounds confusing to users
18:12
<shu>
Andreu Botella: you can't make assignment a hidden clone anyway, because you need to clone it into a particular target realm, and a shared struct assignment is more like a broadcast
18:14
<Andreu Botella>
you'd also want struct.sab === struct.sab, and that would require an extra per-isolate map
18:15
<shu>
yeah
18:16
<Luca Casonato>
You could make the assigment assign the SAB backing store into the shared struct, and then make the property access on the SAB create the JS object on demand - but that sounds slow and ugly and likely difficult to integrate
18:16
<Luca Casonato>
But yeah, to fix identity discontinuity you'd need a backing store -> js object map per isolate
18:18
<shu>
i think the DX of SAB objects themselves just don't matter
18:19
<shu>
since you can only use them via TA objects
18:19
<shu>
so to introduce a new kind of SAB object that can be put into shared structs seems the simplest solution to me
18:20
<littledan>
You could make the assigment assign the SAB backing store into the shared struct, and then make the property access on the SAB create the JS object on demand - but that sounds slow and ugly and likely difficult to integrate
the inability of SAB to point to JS values (with cycle collection) is a fundamental limitation. This is why I like how shared structs do not include the ability to be backed by SABs--it would be a completely different thing.
18:22
<Luca Casonato>
the inability of SAB to point to JS values (with cycle collection) is a fundamental limitation. This is why I like how shared structs do not include the ability to be backed by SABs--it would be a completely different thing.
I don't understand. My comment was about engine internal code, not user code.
18:22
<littledan>
oh sorry I was going on a random tangent because I misunderstood
18:24
<rbuckton>
mark: re yield. I'm not sure what the champion's position is on this, but I think my preference is that context isn't preserved. If it isn't preserved, there's an opportunity for a userland runtime to set context when calling .next(), which could be useful for something like a dataflow library.
18:25
<bakkot>
(I have the opposite preference - yield should not be meaningfully different than await here)
18:25
<rbuckton>
yield is meaningly different from await though.
18:26
<bakkot>
Not for the purposes of this API
18:26
<HE Shi-Jun>
Both sides seems reasonable 😂
18:26
<bakkot>
In both cases the syntax is creating a continuation callback to be called at a future point, and that continuation should capture the current state
18:26
<littledan>
it would probably be helpful to look into the experience in Node.js, where this feature has long existed without such support in yield. Has this led to bugs? We should be able to find out.
18:27
<bakkot>
it would probably be helpful to look into the experience in Node.js, where this feature has long existed without such support in yield. Has this led to bugs? We should be able to find out.
No one uses yield so it doesn't come up
18:27
<littledan>
No one uses yield so it doesn't come up
shouldn't this show up in generators all the time?
18:27
<bakkot>
no one uses generators either
18:28
<rbuckton>
shouldn't this show up in generators all the time?
I'd expect a lot of generators run to completion synchronously, so it wouldn't be observable.
18:28
<rbuckton>
"no one" is far too strong. TypeScript uses them internally, and there are userland runtimes that rely on them.
18:28
<bakkot>
that's an exaggeration of course, but yeah like Ron says most uses of generators IME are simple enough that it doesn't end up being relevant. to see this in real life you have to do the next call on a subsequent turn
18:28
<nicolo-ribaudo>
For generators that are resumed asynchronously, wouldn't the context be preserved by the async helper used to resume the generator (a callback, a promise.then, etc)?
18:30
<yulia>
dumb question: there is no chance that "context" will be confused with the decorators context? Asking because I just heard context so many times and got reminded that it can be kind of meaningless because it can mean anything. Totally not a blocking concern but wondering if anyone else had the same thought
18:30
<rbuckton>
If yield did preserve context, I'd argue we need a mechanism to turn this off on an as-need basis otherwise we'd block a number of valid use cases.
18:30
<ljharb>
are beginner devs using node's async stuff now?
18:30
<bakkot>
I would be OK with a yield.nocontext or something I guess
18:30
<shu>
dumb question: there is no chance that "context" will be confused with the decorators context? Asking because I just heard context so many times and got reminded that it can be kind of meaningless because it can mean anything. Totally not a blocking concern but wondering if anyone else had the same thought
semi-serious: time to resurrect "Conveyance"!!
18:31
<littledan>
dumb question: there is no chance that "context" will be confused with the decorators context? Asking because I just heard context so many times and got reminded that it can be kind of meaningless because it can mean anything. Totally not a blocking concern but wondering if anyone else had the same thought
Yeah it'd be great to have a name brainstorm here (in an issue, not during plenary). https://github.com/tc39/proposal-async-context/issues
18:31
<rbuckton>
I would be OK with a yield.nocontext or something I guess
That's the problem. In the cases I'm concerned with, the generator is provided by the user to a third party library. You want the library to handle the complexities involved with async context flow control, not the author of the genrator. You want them to not be concerned about choosing which yield variant to use.
18:32
<yulia>
i don't have a concrete alternative and context isn't horrible. I don't know if the collision would really take place, just hadn't thought about it
18:32
<rbuckton>
A number of languages with an AsyncContext-like mechanism also have some mechanism of explicitly affecting async flow control.
18:32
<yulia>
i'll make an issue
18:32
<littledan>
The thing is, an AsyncContext instance is more like a single variable
18:32
<HE Shi-Jun>
I would be OK with a yield.nocontext or something I guess
yield.foo will have diff semantic out of generator, don't like such syntax :P
18:33
<rbuckton>
A number of languages with an AsyncContext-like mechanism also have some mechanism of explicitly affecting async flow control.
See https://learn.microsoft.com/en-us/dotnet/api/system.threading.asyncflowcontrol?view=net-8.0, for example.
18:34
<bakkot>
hm. I'll have to think more about yield.
18:34
<bakkot>
I could be convinced it should not wrap, probably
18:34
<rbuckton>
The thing is, an AsyncContext instance is more like a single variable
.NET calls this an AsyncLocal<T>, though that is backed by something called a "Call Context"
18:37
<ljharb>
tbh "context" is a better name for this proposal than for the decorator property, if we had to pick one
18:39
<yulia>
thats fair, up until today i was taking AsyncContext as a name for granted
18:39
<littledan>
let's call it "util"
18:39
<yulia>
oh no, what have i done
18:39
<littledan>
AsyncUtil
18:40
<Ben Newman (Apollo, @benjamn on GH)>
the meaning of "context" is highly context-dependent, unfortunately
18:40
<rbuckton>
context is a general purpose term, I'd hate for us to relegate it to a single purpose.
18:40
<shu>
apaprocki: i believe you but BBG is a closed-shop ecosystem, so i wouldn't weigh it too much as predictive of ecosystem integration pains for JS at large
18:41
<apaprocki>
understood, merely relaying experience that for the end users, who are really just writing JS, it wasn't confusing for them to understand why it wasn't working and how to fix it
18:50
<ljharb>
eemeli: pretty sure it's not polyfillable
18:52
<bakkot>
That's the problem. In the cases I'm concerned with, the generator is provided by the user to a third party library. You want the library to handle the complexities involved with async context flow control, not the author of the genrator. You want them to not be concerned about choosing which yield variant to use.

so, "the generator is provided by the user to a third party library" seems like exactly the case where we want yield to preserve state. taking the example from the readme:

  libraryTakingAnIterator(context.run('id', function* () {
    log('starting');

    yield 0;

    // if the library `await`s before resuming, we've lost our id
    log('done');
  }));

Maybe we should say that any library which consumes iterators in this way needs to juggle contexts properly? but on the other hand it's not clear to me how that's even possible here - how would the library ensure that the second half of the generator runs in the correct context?

18:52
<Ben Newman (Apollo, @benjamn on GH)>
strawdog idea: you could wrap Generator.prototype.next
18:53
<bakkot>
but how does the library get the original context?
18:53
<littledan>
when the queue opens back up, please feel free to ask questions about AsyncContext, even much more basic ones, about how it works at all.
18:53
<rbuckton>
I'd expect, at least roughly, that the context value remains referenced until run's callstack is exhausted and any Promise created is garbage collected.
18:55
<rbuckton>

so, "the generator is provided by the user to a third party library" seems like exactly the case where we want yield to preserve state. taking the example from the readme:

  libraryTakingAnIterator(context.run('id', function* () {
    log('starting');

    yield 0;

    // if the library `await`s before resuming, we've lost our id
    log('done');
  }));

Maybe we should say that any library which consumes iterators in this way needs to juggle contexts properly? but on the other hand it's not clear to me how that's even possible here - how would the library ensure that the second half of the generator runs in the correct context?

Hmm. that example feels odd to me, since execution for the generator doesn't actually start until you call .next(). That said, I'm fine if context propagates over yield if we have a mechanism to affect async flow control.
18:56
<ryzokuken>
note: we'll have to go upto 10m into lunch because of the delays
19:01
<justinfagnani>
is anyone else not seeing the slides on Zoom?
19:01
<Jesse (TC39)>
yeah
19:01
<Jesse (TC39)>
oops, I mean, I am seeing the slides
19:01
<danielrosenwasser>
quick refresh?
19:02
<justinfagnani>
ah, that did it
19:02
<justinfagnani>
thanks
19:04
<shu>
i would like the conversation to come back to what littledan was proposing on "whether we want this feature"
19:04
<shu>
all these details beg the question of our already having consensus on that
19:04
<bakkot>
I do wish we had more examples yeah
19:04
<bakkot>
this is a big complex thing
19:04
<bakkot>
so I want to see it being useful for a bunch of things
19:05
<bakkot>
and I trust justin that it is useful for all the enumerated things, but I can't visualize how yet
19:05
<littledan>
Chengzhong Wugave a good presentation in WebPerfWG about this
19:05
<rbuckton>
Hmm. that example feels odd to me, since execution for the generator doesn't actually start until you call .next(). That said, I'm fine if context propagates over yield if we have a mechanism to affect async flow control.
Actually, if yield propagates context then I'm not even sure a flow-control mechanism would help, since flow control would probably only affect entry to the generator, not reentry via next().
19:05
<littledan>
Maybe next meeting, this can be given to TC39 again
19:07
<Lenz Weber-Tronic (phryneas)>
bakkot the most pressing issue I can think of at this time is in servers, where functions need to access stuff related to the current request. At this point it's an absolute pain of passing the current request context down and down and down in method arguments, and it's easily lost.
19:07
<Lenz Weber-Tronic (phryneas)>
node has AsyncLocalStorage for that, but any framework that wants to support more platforms than that is at a loss at this time.
19:09
<bakkot>
Lenz Weber-Tronic (phryneas): I believe you but I need to see it written out
19:09
<justinfagnani>
there's both a question why it's useful, but why it's valuable as a language feature (which is the inability of userland code to correctly wrap all closure-storing APIs or intercept await)
19:09
<rbuckton>
bakkot: I've used to thread request context information for web requests, such as the current authenticated user, request message, etc. Similar to HttpContext.Current in .NET (which uses the same mechanisms)
19:09
<justinfagnani>
Angular's zones.js problems with await as an example
19:10
<Andreu Botella>
shu: Chengzhong Wu and me are going to prototype a V8 implementation to see performance and integration with task attribution
19:11
<Lenz Weber-Tronic (phryneas)>
bakkot how exactly would "written out" look in this case? Just trying to figure out how to best give you the example.
Imagine you have a call stack that is 50 calls deep. Either you have a , context argument in every of those functions, or the one function at depth 50 can call getCurrentRequest() which wraps requestContext.get()
19:11
<bakkot>
Lenz Weber-Tronic (phryneas): written out meaning, like, code
19:11
<shu>
Andreu Botella: in blink as well? any benchmarks in mind?
19:11
<danielrosenwasser>

I very much don't have expertise to weigh in on this API, so I can just give trust that in the current direction; but it sounds like the feature works "in the abstract". I wish there was a prototype or sample codebase so that we could have a sample in which it could be demonstrated:

  • "now let's add logging"
  • "now let's add ..."

and see how that composes in practice. And I'm fine with discussing that in stage 2.

19:11
<littledan>
Andreu Botella: in blink as well? any benchmarks in mind?
In blink: Yes. Benchmarks: welcome.
19:12
<bakkot>
i.e. assume this API exists. what does code using it look like, concretely, that would run if it were in the language
19:12
<shu>
littledan: it can't be just "welcome", i'm asking how andreu plans to "see performance"?
19:12
<shu>
we know it's possible to implement
19:13
<apaprocki>
i.e. assume this API exists. what does code using it look like, concretely, that would run if it were in the language
You could survey usage of Node's API for example code, since it essentially provides the same functionality
19:13
<littledan>
littledan: it can't be just "welcome", i'm asking how andreu plans to "see performance"?
OK, well, yeah, this is a reasonable requirement, and we should look into it. Keeping performance good is a goal as Justin has repeatedly said. Bloomberg is sponsoring Igalia's involvement in implementation work.
19:13
<littledan>
and yeah the burden should be on us to prove that it's good.
19:13
<Andreu Botella>
Yeah, we'll be looking into that. We don't yet have any benchmarks in mind, but this is still very early on
19:13
<Andreu Botella>
like, we were literally discussing this earlier today
19:13
<Lenz Weber-Tronic (phryneas)>

bakkot it does exist, in some form, in node

An example would be the NextJs headers function. This functionality would not be able at all in React-land without this API:
https://beta.nextjs.org/docs/api-reference/headers

19:13
<shu>
it doesn't have to be a real benchmark
19:14
<shu>
i'm just wondering how you plan to verify anything
19:14
<shu>
(not being flippant if i sounded that way)
19:14
<Chengzhong Wu>
In Node.js we have several micro-benchmarks that we can port to AsyncContext: https://github.com/nodejs/node/tree/main/benchmark/async_hooks
19:15
<Chengzhong Wu>
And we can adopt OpenTelemetry's real world use cases for benchmarking if needed.
19:15
<shu>
sorry let me be clearer
19:16
<shu>
the performance concern is not that AsyncContext itself will be too slow
19:16
<shu>
it's fine for new features to be slow
19:16
<shu>
the way this feature must be implemented is In The Deep at the engine level
19:16
<shu>
which means it affects performance of all executions even if they don't use the feature
19:17
<shu>
i would like to see things that suggest that this feature can in fact be pay-as-you-go (or close to it), and executions that don't use the feature don't suffer performance regressions
19:17
<shu>
oops, missed an operative "not" above
19:17
<Ben Newman (Apollo, @benjamn on GH)>
V8 is already saving/restoring the v8::Context::{Get,Set}ContinuationPreservedEmbedderData today, which is close to what this proposal needs
19:17
<shu>
please, i know how V8 works
19:17
<Ben Newman (Apollo, @benjamn on GH)>
I know!
19:18
<littledan>
Yeah, it will be a clear requirement that this doesn't slow down V8. We can the existing public V8 benchmarks to verify (and I know you have CI that will also verify this after it lands).
19:18
<shu>
but that thing is set by the embedder in a very bounded way, in a way that V8 folks aren't 100% happy with anyway
19:18
<shu>
for this to become JS programmable opens up new unknowns we should understand
19:18
<littledan>
I'm very encouraged by how TaskAttribution landed and is always on in Chrome, apparently without performance overhead
19:18
<Ben Newman (Apollo, @benjamn on GH)>
fair enough / good to know
19:18
<littledan>
but that thing is set by the embedder in a very bounded way, in a way that V8 folks aren't 100% happy with anyway
Would be great to learn in what way V8 folks aren't happy with it for now
19:19
<shu>
fair, i'll try to understand this unhappiness deeply so i can articulate it
19:20
<Justin Ridgewell>
Yeah it'd be great to have a name brainstorm here (in an issue, not during plenary). https://github.com/tc39/proposal-async-context/issues
As long as we don't call this AsyncLocalStorage, which is AsyncLocal-Storage and not Async-LocalStorage.
19:21
<HE Shi-Jun>
I still like AsyncLocal which make the analog to ThreadLocal in other langauges.
19:21
<HE Shi-Jun>
We don't have notes of current topic?
19:22
<Justin Ridgewell>

so, "the generator is provided by the user to a third party library" seems like exactly the case where we want yield to preserve state. taking the example from the readme:

  libraryTakingAnIterator(context.run('id', function* () {
    log('starting');

    yield 0;

    // if the library `await`s before resuming, we've lost our id
    log('done');
  }));

Maybe we should say that any library which consumes iterators in this way needs to juggle contexts properly? but on the other hand it's not clear to me how that's even possible here - how would the library ensure that the second half of the generator runs in the correct context?

I think the more natural is to do context.run(libraryTakingAnIterator(…)), in which case both call and init time would be equivalent
19:22
<Andreu Botella>
An "async context" in common parlance would seem to refer to the entire async-local map, rather than to an entry
19:22
<Andreu Botella>
so there's also that
19:22
<Justin Ridgewell>
We don't have notes of current topic?
It's lunch, not an official presentation
19:24
<HE Shi-Jun>
It's lunch, not an official presentation
ok, though I would like it also have the notes (I use notes as subtitle :)
19:25
<HE Shi-Jun>
especially zoom do not have auto subtitle :(
19:25
<Justin Ridgewell>
shu: Chengzhong Wu and me are going to prototype a V8 implementation to see performance and integration with task attribution
My hope is that this will literally have 0 performance penalty for code not using AsyncContext, and be like 0.00001% slowdown for code that is.
19:26
<Justin Ridgewell>
I believe the current node addon impl has that guarantee
19:26
<Ben Newman (Apollo, @benjamn on GH)>
possible jargon to distinguish between whole-map and individual items: "supertext" (not a real word) and "subtext"?
19:26
<Ben Newman (Apollo, @benjamn on GH)>
I agree this is a common ambiguity when talking about context, even at a linguistic level
19:31
<Justin Ridgewell>
Zoom does, but I don't know how to enable it
19:41
<shu>
my hope goes with you
19:45
<shu>

waldemar: so, re: the C++ release fence. in short, you are correct that in the C++ memory model the release fence doesn't sync-with without a corresponding acquire operation on another thread.

the way V8 (and JVM) reason about this i think is more at the ISA level, per ISA. like, we think a store-store fence (dmb on ARM) or whatever is sufficient to publish. we need to ensure no store-store reorderings happen at both the codegen level and the CPU level.

the dmb guarantees that at the CPU level. a release fence seems to guarantee that at the codegen level, but strictly speaking may be incorrect.

maybe manual inline assembly is better here? idk

19:45
<shu>
in any case V8 mixes C++ generated code and our own generated code liberally anyway, since it's a JIT
19:45
<shu>
and i've never wrapped my head around reasoning at the C++ memory model level
19:45
<shu>
because of course taht doesn't exist for our own generated code
19:45
<shu>
so i generally try to reason about it by divining what ARM guarantees, then trying to shape C++ to generate the right thing
19:46
<shu>
(or what x86 guarantees etc)
19:47
<shu>
in fact, V8 also does the even more un-specified thing around atomics where we just bitcast addresses to std::atomics
19:47
<shu>
but i think that behavior may finally be getting specced?
19:53
<shu>
omg it's this sub-thread that was keeping my notification at 1
19:54
<shu>
and now i've made it worse for other people, sorry
19:59
<rbuckton>
I may be a minute or two late getting back. My dogs need a bio break and don't care about the plenary schedule.
20:02
<rbuckton>
I may be a minute or two late getting back. My dogs need a bio break and don't care about the plenary schedule.
I'm back
20:08
<bakkot>
ljharb: was it es-shims which deletes it? for the notes
20:08
<ljharb>
es6-shim, specifically. core-js may, i'm not sure
20:09
<bakkot>
(I just missed the name)
20:09
<Justin Ridgewell>
my hope goes with you
Worth also noting is that node is already eating performance with usage of AsyncLocalStorage, my apps are losing native async/await performance due to my need to polyfill
20:09
<littledan>
Worth also noting is that node is already eating performance with usage of AsyncLocalStorage, my apps are losing native async/await performance due to my need to polyfill
Sure, but we also need to make sure that this doesn't make websites slower
20:09
<Justin Ridgewell>
We already live in a slow world, and this API should be much faster than the status quo
20:09
<shu>
the hard line is "no speedometer regressions"
20:09
<shu>
hard-ish
20:10
<littledan>
the hard line is "no speedometer regressions"
Very helpful to have this line--should be easy to develop against.
20:10
<shu>
godspeed you! async contexter
20:11
<littledan>
what is this referencing?
20:11
<shu>
https://en.wikipedia.org/wiki/Godspeed_You!_Black_Emperor
20:12
<Jesse (TC39)>
great stuff
20:12
<Ben Newman (Apollo, @benjamn on GH)>
the ! placement triggered the memory for me
20:17
<shu>
does anyone have a link to these slides?
20:17
<ryzokuken>
does anyone have a link to these slides?
https://docs.google.com/presentation/d/1b74GI-zHrG0wDzmwFs_yPWRli24KyVUNx3GeZt8JouA/edit#slide=id.g2227767b447_1_6
20:18
<shu>
ty
20:18
<Justin Ridgewell>
I was always more into Explosions in the Sky
20:23
<Chris de Almeida>
< 10 mins for this item
20:27
<rbuckton>
Is ns precision useful to scientific calculations, or are they more likely to depend on sub-nanosecond values?
20:28
<bakkot>
re: nanoseconds and microseconds, https://www.youtube.com/watch?v=9eyFDBPk4Yw
20:29
<rbuckton>
More to the point that computer-derived wall clock time isn't the only source of time that Temporal.Instant and .Duration might be useful for.
20:29
<littledan>
I think the interop case doesn't really relate to durations
20:30
<bakkot>
I'm sorry, quarter nanoseconds?
20:30
<bakkot>
why
20:30
<littledan>
it fit into the bits?
20:30
<bakkot>
https://github.com/abseil/abseil-cpp/blob/b6de7b80325514018d38de2c4dee1254258c4b31/absl/time/duration.cc#L30-L31
20:30
<bakkot>
sigh
20:30
<bakkot>
yeah that's the reason
20:31
<apaprocki>
yeah, they decided to do that.. in our equivalent class, we opted just for storing nanoseconds and not quarterns like abseil
20:31
<rbuckton>
That and the following two lines about calculating fractional nanoseconds, but I suppose that wouldn't matter if they didn't have fractional nanoseconds to begin with.
20:32
<shu>
that abseil thing exactly characterizes where the interop argument falls down when you tug on the chain
20:32
<shu>
"why did they do it? well... because it fit" is not a good first principles argument
20:32
<shu>
but anyways we'll have ns
20:33
<Richard Gibson>
does abseil expose that data or just keep it internally for arithmetic?
20:33
<apaprocki>
it wasn't just because it fit, but because they stated a need for 0.5 ns + 0.5 ns
20:33
<apaprocki>
they didn't explain where they have that requirement
20:33
<apaprocki>
just that it exists
20:33
<shu>
v8's position is there is no good reason, and certainly not on the web
20:34
<littledan>
that abseil thing exactly characterizes where the interop argument falls down when you tug on the chain
I think interop where there's no standard is the kind of case where you can choose a preponderance-of-the-evidence kind of thing. ns is "good enough" in this sense. That doesn't make it a reductio-ad-absurdum
20:34
<littledan>
v8's position is there is no good reason, and certainly not on the web
I think half-microseconds aren't really that implausible to be relevant. Anyway there are lots of times where you're processing date/times without measuring them locally.
20:34
<shu>
the philosophical objection is actually stronger than than "there might be uses"
20:35
<shu>
it's "where you think you should be using nanoseconds, you are fooling yourself with the extra precision, with very few exceptions"
20:35
<littledan>
yeah I guess I see that and don't like the philosophy.
20:35
<shu>
yes, and we don't have consensus on it anyways
20:35
<apaprocki>
it's "where you think you should be using nanoseconds, you are fooling yourself with the extra precision, with very few exceptions"
except where law/regulations say they must be passed around... it's not about philosophy, but about preventing foot guns when moving values from one system to another through js
20:35
<shu>
that doesn't relate to temporal
20:36
<shu>
you can use BigInts
20:36
<littledan>
yes, and we don't have consensus on it anyways
well, I am glad you all brought the point up anyway, and that we were able to discuss it and come to a conclusion
20:36
<shu>
except where law/regulations say they must be passed around... it's not about philosophy, but about preventing foot guns when moving values from one system to another through js
i don't understand this argument, you and others have repeatedly brought this up. why... are people shoehorning everything that represents time into Temporal data types?
20:37
<shu>
like ns timestamps don't need the extra complexity of temporal
20:37
<shu>
sometimes it's formatting
20:37
<shu>
which... is a different thing?
20:37
<apaprocki>
because you are generically binding to typed database tables or schemas for services, etc. it's a giant foot gun if developers can't take a duration from Postgres and represent it as a duration in js without loss
20:37
<apaprocki>
somehow knowing they need to not use the built-in type and use a string or unrelated type.. it's extremely not ergonomic
20:38
<littledan>
this is one of the key reasons for it being in the standard library rather than just telling people to use Moment
20:38
<shu>
first of all, postgres is ms precision?
20:38
<waldemar>
Indiana has (at least) 11 time zones: https://en.wikipedia.org/wiki/Time_in_Indiana
20:39
<apaprocki>
first of all, postgres is ms precision?
no, everything now uses ns
20:39
<Chris de Almeida>
🙊
20:39
<shu>
oh really?
20:39
<apaprocki>
yes.. haven't found a modern system that hasn't already upgraded (if they didn't start out ns)
20:39
<apaprocki>
like rust had the benefit of starting with ns because it started much later, but python upgraded over time via PEPs
20:40
<shu>
anyway we're not going down microseconds road
20:40
<bakkot>
no, everything now uses ns
hm https://www.postgresql.org/docs/current/datatype-datetime.html
20:40
<shu>
and i would like to evict this conversation from my brain
20:40
<bakkot>
shu: good good, gotta make room for the conversation about time zone name canonicalization differences between TZDB and CLDR
20:40
<shu>
i am having lunch
20:41
<apaprocki>
hm https://www.postgresql.org/docs/current/datatype-datetime.html
"time, timestamp, and interval accept an optional precision value p which specifies the number of fractional digits retained in the seconds field. By default, there is no explicit bound on precision. The allowed range of p is from 0 to 6."
20:43
<apaprocki>
there is an extension that allows up to 9
20:43
<bakkot>
ah that's what I get for not reading past the table
20:44
<ryzokuken>
there is an extension that allows up to 9
https://github.com/fvannee/timestamp9
20:46
<apaprocki>
there's a bit of drift between databases (unlike programming languages).. oracle supports ns fully, mssql is 100 ns precision iirc, but the point is that they are < 1us
20:53
<Chris de Almeida>
10 mins on this item
21:05
<apaprocki>
justingrant: thanks for doing this! Literally just starting the 2023a firedrill right now... :D
21:10
<bakkot>
how do people feel about parameter decorators
21:10
<Chris de Almeida>
cautiously... cautious
21:12
<justingrant>
justingrant: thanks for doing this! Literally just starting the 2023a firedrill right now... :D
Thanks! Hopefully this proposal can reduce the firedrill pain in the future.
21:13
<ljharb>
i feel a lot better about parameter decorators than i do about supporting/encouraging DI patterns
21:13
<shu>
how do people feel about parameter decorators
somewhere between "maybe okay if sufficiently restricted" and "i'm straight up not having a good time"
21:17
<ljharb>
something i do want is the ability to mark constructor arguments as automatically stored in a public, or private, field. but that could be done potentially with a class decorator, i suppose
21:18
<Lenz Weber-Tronic (phryneas)>
something i do want is the ability to mark constructor arguments as automatically stored in a public, or private, field. but that could be done potentially with a class decorator, i suppose
Could that class decorator know the name of those constructor parameters?
21:18
<HE Shi-Jun>
how do people feel about parameter decorators
We discussed it in JSCIG meeting and it seems many TS users like it .
21:18
<littledan>
how do people feel about parameter decorators
They seem kinda cool but I really want function decorators and, separately, extractors/pattern matching, which are kind of in adjacent spaces. Probably all of this eventually; I don't know how to prioritize.
21:19
<ljharb>
Could that class decorator know the name of those constructor parameters?
in my ideal world an explicit constructor would be omitted, so the class decorator would define the names
21:19
<littledan>
parameter decorators, or something else in this space, are definitely part of the program of, "how do we find a standard, unified way to solve all of the problems that people are widely doing through language extensions"
21:19
<shu>
as a general philosophy i do not want more and more metaprogramming needing to be supported at runtime
21:19
<HE Shi-Jun>
I also want function decorators. 😀
21:19
<Lenz Weber-Tronic (phryneas)>
how do people feel about parameter decorators
They are very commonly used in code I have touched over the last few years. I think the code would have been significantly more complicated without them.
21:20
<shu>
my hot take is that we need to standardize different phases of evaluation in JS
21:20
<bakkot>
They are very commonly used in code I have touched over the last few years. I think the code would have been significantly more complicated without them.
I have the exact opposite experience
21:21
<bakkot>
parameter decorators, or something else in this space, are definitely part of the program of, "how do we find a standard, unified way to solve all of the problems that people are widely doing through language extensions"
wait I don't want that program
21:21
<bakkot>
I never signed up for that program
21:21
<HE Shi-Jun>
as a general philosophy i do not want more and more metaprogramming needing to be supported at runtime
It seems if we have class decorators, people eventually would ask for "decorate everything".
21:21
<bakkot>
I am explicitly opposed to solving all of the problems that people are doing through language extensions
21:21
<ljharb>
showing me lots of code examples that are ExcessiveNounHavers doesn't make me feel good about the patterns :-/ just because a lot of people write X code in JS doesn't mean JS should support patterns common in X codebases.
21:21
<shu>
It seems if we have class decorators, people eventually would ask for "decorate everything".
and?
21:21
<littledan>
I am explicitly opposed to solving all of the problems that people are doing through language extensions
not all, just the good ones. And sometimes doing things differently, for sure.
21:22
<Chris de Almeida>
I'm generally apprehensive about too much hidden magic that makes grok difficult for grug brain
21:22
<shu>
sorry i'm being very flippant this meeting
21:22
<bakkot>
DI is the canonical example of hidden magic ime
21:22
<Lenz Weber-Tronic (phryneas)>
I have the exact opposite experience

NestJS has some very nice usages, fore example the @Param decorator in route handlers: https://docs.nestjs.com/controllers


@Get(':id')
findOne(@Param('id') id: string): string {
  return `This action returns a #${id} cat`;
}
21:22
<bakkot>
like I have used it in talks as an example of that thing
21:22
<shu>
yes
21:22
<bakkot>

NestJS has some very nice usages, fore example the @Param decorator in route handlers: https://docs.nestjs.com/controllers


@Get(':id')
findOne(@Param('id') id: string): string {
  return `This action returns a #${id} cat`;
}
you and I have a different understanding of what counts as "nice", I think
21:22
<Lenz Weber-Tronic (phryneas)>
But I agree that there are very ugly examples as well
21:22
<shu>
more generally this all strikes me as optimizing for the author
21:23
<littledan>
DI is the canonical example of hidden magic ime
well, unfortunately for you (maybe), we already enabled Ember's instance field decorator-style DI through field decorators!
21:23
<shu>
which is the wrong audience to optimize for
21:23
<shu>
sometimes it's, like, not too bad
21:23
<shu>
in this case it is bad
21:23
<littledan>
I do have to admit that, with decorators evaluated at class evaluation time, they are sort of a better fit than extractors/pattern matching evaluated each time the function runs.
21:24
<ljharb>
i think param decorators and param pattern matching/extractor "something" are quite different
21:24
<ljharb>
the use cases, anyways, even if the capabilities are similar
21:24
<littledan>
more generally this all strikes me as optimizing for the author
??? isn't this sort of a core goal of programming language design? Like, if it's at the expense of the end user (e.g., for performance), then that's bad, but all else being equal, we do want to optimize for the author?
21:25
<ljharb>

imo we want to optimize for the person reading/maintaining the code after the author produces it

that's a far more frequent and important audience.

21:25
<bakkot>
??? isn't this sort of a core goal of programming language design? Like, if it's at the expense of the end user (e.g., for performance), then that's bad, but all else being equal, we do want to optimize for the author?
no we mostly want to optimize for the reader
21:25
<ljharb>
iow, writability < < < readability
21:25
<littledan>
oh you meant author at the expense of reader!
21:25
<shu>
yes, correct
21:25
<danielrosenwasser>
I was also a little confused
21:25
<danielrosenwasser>
maybe all the Daniels were confused
21:25
<Chris de Almeida>

imo we want to optimize for the person reading/maintaining the code after the author produces it

that's a far more frequent and important audience.

counterpoint: that's often the same audience
21:25
<ljharb>
code that's easy to write but hard to read is not what i would call good code
21:25
<shu>
sorry, not author vis a vis user, but writer vs reader
21:26
<ljharb>
counterpoint: that's often the same audience
"me" and "me in 6 months" are not the same audience, and "met in 6 months" is often angry at the code i write
21:26
<littledan>
Yeah, I mean, I wouldn't really be a fan of some of the decorators used in this presentation
21:26
<HE Shi-Jun>
and?
And I think it's reasonable to have param decorators, function decorators, etc. if we support class decorators...
21:26
<Chris de Almeida>
fair
21:27
<shu>
what is the argument for it?
21:27
<shu>
"people ask for it" is usually not sufficient
21:28
<ljharb>
JS also is in a position where a ton of people come to it from different languages, and they write lots of code that matches the idioms of their source langs that does NOT match JS idiom
21:28
<ljharb>
ie the "java devs write java in every language" sentiment (not just picking on java here, ofc)
21:28
<Chris de Almeida>
ImplImplImplImplBuilderImpl
21:29
<ljharb>
excessive nouns, indeed
21:29
<apaprocki>
I'd say something like "it allows you to easily reuse code that would otherwise be repeated (boilerplate), or, more importantly, omitted because the author doesn't want to bother due to the size of the boilerplate"
21:29
<apaprocki>
for things like standard parameter validation checks across a large codebase
21:29
<ljharb>
validation checks i 100% agree - that's not the same thing as the extensive metaprogramming demonstrated in the preso
21:29
<littledan>
JS also is in a position where a ton of people come to it from different languages, and they write lots of code that matches the idioms of their source langs that does NOT match JS idiom
Another way to frame this would be, "The culture of how people write JS is diverse and influenced by other programming languages' culture"
21:30
<bakkot>
valid(x) is almost exactly the same amount of code as @valid, and as a bonus also works with destructured parameters
21:30
<ljharb>
sure. it's just not necessarily influenced for the better.
21:30
<Ashley Claymore>
I do have to admit that, with decorators evaluated at class evaluation time, they are sort of a better fit than extractors/pattern matching evaluated each time the function runs.
the function returned by the decorator does run each time, so a bit like a cached extractor
21:30
<Lenz Weber-Tronic (phryneas)>
validation checks i 100% agree - that's not the same thing as the extensive metaprogramming demonstrated in the preso
well, people had 10 years to come up with stuff, the presentation is just showing what people are already doing - and I guess showing the obvious and boring would not make a good case that it is a flexible tool, right? :)
21:30
<Chris de Almeida>
agree that validation seems reasonable as does ORM use case.. request mapping.. I have trouble imagining how the scope can be narrowed though
21:31
<shu>
i deeply hate ORM
21:31
<shu>
but that's personal
21:31
<HE Shi-Jun>
maybe all the Daniels were confused
I was also confused.
21:31
<littledan>
the function returned by the decorator does run each time, so a bit like a cached extractor
right--it'd be nice if extractors could be cached, but that somehow doesn't make as much sense syntactically
21:31
<ljharb>
obligatory https://seldo.com/posts/orm_is_an_antipattern/
21:31
<bakkot>
sidebar: this is I think way too much detail for a stage 1 presentation
21:31
<Jesse (TC39)>
i like the idea of ORM but have never found one that meshes with how I want it to work
21:31
<Chris de Almeida>
what do you mean you don't like doing a complete 1-1 of your data model in the frontend?
21:32
<bakkot>
stage 1 needs like 1 slide on potential API
21:32
<ljharb>

i mean, look at all the times use of an ORM has allowed a seamless transition between backing databases!

21:32
<bakkot>
2 maybe
21:32
<shu>
sidebar: this is I think way too much detail for a stage 1 presentation
+1, there are very high-level foundational concerns being raised in the matrix
21:32
<shu>
i should think that deserves discussion time more than detailed semantics
21:32
<Chris de Almeida>
you've convinced me
21:33
<apaprocki>
sidebar: this is I think way too much detail for a stage 1 presentation
my gut is telling me people are erring way more on the side of TMI to fend off potential motivation concerns up front
21:33
<bakkot>
I have probably been guilty of this too because I fall in love with proposals and flesh them all out in my head before bringing them to committee
21:33
<bakkot>
but that stuff mostly ought to go in the repo rather than the presentation
21:34
<littledan>
to be fair to Ron, this is 9 years coming; this is very thought out even if we are having a hard time processing it all at once.
21:35
<Justin Ridgewell>
Does anyone else get a strong "corporate java project" vibe from the code?
21:35
<Justin Ridgewell>
I really need to catch up with this matrix logs
21:36
<HE Shi-Jun>
sidebar: this is I think way too much detail for a stage 1 presentation
but if not show many use cases people will refuse it because of no enough use cases??
21:36
<shu>
naive question: can you "just like" parse the parameters of the toString()'d original method in a method decorator, and... use that?
21:37
<bakkot>
but if not show many use cases people will refuse it because of no enough use cases??
the use cases part was good and appropriate
21:37
<bakkot>
the "here is what the type of the target field should be" part is less appropriate
21:37
<ljharb>
naive question: can you "just like" parse the parameters of the toString()'d original method in a method decorator, and... use that?
yes, but that's what angular 1 did, and it's horrific and breaks whenever minification happens
21:37
<shu>
ah, indeed, minification
21:37
<shu>
thanks
21:39
<ptomato>
Does anyone else get a strong "corporate java project" vibe from the code?
I mean I think DI is a very divisive programming technique? but IMO we should separate "this proposal would enable X footgun" and "this proposal would enable X programming technique that I don't like"
21:40
<bakkot>
the latter is also a valid reason to not add something though
21:40
<bakkot>
e.g., there are languages where constructing code at runtime and evaluating it is a core technique
21:41
<Chris de Almeida>
I do not miss the era of DI being the new shiny
21:41
<bakkot>
but I don't want people to use that technique in JS and would actively oppose features which enabled it (though, of course, that ship has sailed)
21:41
<Justin Ridgewell>
https://matrix.to/#/!WgJwmjBNZEXhJnXHXw:matrix.org/$ub45qHDXteYxSbmwfzPGXe-KTZXA2oRYer99mr5tPrY?via=matrix.org&via=igalia.com&via=mozilla.org
21:43
<Justin Ridgewell>
I mean I think DI is a very divisive programming technique? but IMO we should separate "this proposal would enable X footgun" and "this proposal would enable X programming technique that I don't like"
I think bakkot's point is also spot on. Java has an overuse of classes for everything, and this is shoehorning a bunch into functionality into classes because we want it to be class method param decorators
21:44
<Justin Ridgewell>
I'm not blocking, but god I hope I never have to work on a codebase that uses this style.
21:45
<Lenz Weber-Tronic (phryneas)>
but I don't want people to use that technique in JS and would actively oppose features which enabled it (though, of course, that ship has sailed)
I'd say there are frameworks heavily based on that, and also frameworks for the same purpose not using this at all. You probably won't get happy working in a team that loves using these techniques, but that team would find ways of doing so either way - so why not make it easier for them? It will not eradicate the option of working without these features.
21:47
<ljharb>
btw for function decorators can we just decide that decorated function declarations aren't hoisted? or is it more complex than that
21:48
<shu>
that would be extremely weird
21:48
<shu>
that means decorated functions declarations become non-letrec'ed together
21:48
<shu>
which is... extremely weird
21:49
<Justin Ridgewell>
I've used a lot of function foo() { foo = function () {} } memoized declaration wrappers, and I'd like to stop doing that.
21:51
<bakkot>
I'd say there are frameworks heavily based on that, and also frameworks for the same purpose not using this at all. You probably won't get happy working in a team that loves using these techniques, but that team would find ways of doing so either way - so why not make it easier for them? It will not eradicate the option of working without these features.
the "that technique" in the bit you quoted was "constructing code at runtime and evaluating it"
21:51
<bakkot>
and like
21:51
<bakkot>
I think we should not make it easier for them so that they don't do it
21:52
<Lenz Weber-Tronic (phryneas)>
the "that technique" in the bit you quoted was "constructing code at runtime and evaluating it"
Oh, sorry, I missed the first sentence of that message and assumed you still were talking about the current proposal.
21:53
<bakkot>
yeah, the point was that sometimes features enable you to do things that we, as language designers, don't want to encourage you to do. that is how I feel about this style of DI.
21:59
<msaboff>
TypeScript ≠ JavaScript. They don't need to be the same. I think that would be a false goal of the committee. They serve different purposes. Developers choose various tools and language extensions in solve their problems.
22:02
<shu>
i think that's a 4d chess space that deals with developer mindshare and respective tech giants' soft power etc
22:02
<shu>
i have a hard time, attractive as it is, to adopt a more absolutist line like TS and JS can and should just stay separate
22:03
<bakkot>
My hope is that new projects don't adopt TS decorators
22:03
<bakkot>
Old projects staying on TS decorators I don't really have a problem with
22:03
<msaboff>
Maybe I should say that we shouldn't add something to JS because it is in TS, ...
22:04
<shu>
agreed
22:04
<littledan>
TS and JS are pretty aligned already, and this is important and valuable for Bloomberg. But yes I agree completely that we shouldn't just upstream TS features into JS uncritically.
22:04
<shu>
i take msaboff's statement to be stronger than that
22:05
<Lenz Weber-Tronic (phryneas)>
Luckily, there are only two TS runtime features that are not JS features, decorators being one of them - so that's not a long-term concern :)
22:06
<shu>
in your opinion, do you think that is a stable equilibrium
22:06
<Lenz Weber-Tronic (phryneas)>
The TS team committed to not adding anything before ECMAScript Stage 3 half a decade ago, and so far they kept that
22:07
<HE Shi-Jun>
but I don't want people to use that technique in JS and would actively oppose features which enabled it (though, of course, that ship has sailed)
I agree, yes the ship has sailed. I would accept JS never have decorators, but if we already have class decorators, it's wrong to me to not having function decorators, param decorators, etc.
22:10
<HE Shi-Jun>
that would be extremely weird
yeah, it's weird but JS have many such weirdness as prior arts 😂
22:11
<Justin Ridgewell>
Ashley Claymore: I would love if calling Promise.all({ foo: bar }) just worked like MM suggests
22:12
<msaboff>
Maybe I'm pushing back an a theme that seems to be prevalent during this meeting, and that is JS should unify the related ecosystems. I think that is the wrong target. We need to be about craeful evolution of the JS language and ensuring compatibility among the various implementations. That requires saying NO to some proposals for a variety of valid reasons.
22:17
<rbuckton>
something i do want is the ability to mark constructor arguments as automatically stored in a public, or private, field. but that could be done potentially with a class decorator, i suppose
I've experimented with this. Its easy to do on a simple class, but much harder to support an inherited class without injecting a function in between the super and subclass to perform initialization after super().
22:19
<HE Shi-Jun>
Ashley Claymore: I would love if calling Promise.all({ foo: bar }) just worked like MM suggests
I already suggest that in the issue.
22:19
<HE Shi-Jun>
Oh it was closed, could champion reopen that ?
22:19
<Chris de Almeida>
I think there was an item above this
22:20
<bakkot>
I agree, yes the ship has sailed. I would accept JS never have decorators, but if we already have class decorators, it's wrong to me to not having function decorators, param decorators, etc.
again by "that ship has sailed" I meant that we had eval
22:20
<bakkot>
but that said, in exactly the same way, I don't want us to add new ways to make it easier to have eval
22:21
<bakkot>
this is the same way I feel regarding the argument that we have method decorators so should also have parameter decorators
22:22
<rbuckton>

This was going to be my point about the potential of parameter decorators to maybe have better performance than assert, since the conditions expressed in the decorator are cached for every call, as opposed to needing to be reevaluated each time.
They are also simpler, since you can reference the parameter name from context, rather than duplicate it in an assert:

class C {
  method(x) {
    assert(typeof x === "number", "expected x to be a number")
  }
  // vs
  method2(@IsNumber x) { } // already knows the name 'x', no repetition.
} 
22:22
<ljharb>
Oh it was closed, could champion reopen that ?
it's still mostly a nonstarter because of the bug thing; certainly we can keep discussing it tho
22:24
<bakkot>
ljharb doesn't the "if there's more than one argument and the first is not iterable, throw" mostly address the bug thing?
22:24
<ljharb>
yes potentially, i haven't discussed it with ashley yet
22:25
<justinfagnani>
Decorators are ultimately about targeted/declarative meta-programming. Without them we'd have no way to ergonomically metaprogram over class fields (and before accessor no way at all). Is it not in scope to metaprogram in a similar way over parameters?
22:25
<rbuckton>
to be fair to Ron, this is 9 years coming; this is very thought out even if we are having a hard time processing it all at once.
I've had other proposals fail to advance explicitly because of a lack of sufficient real world examples, so I may have overcorrected a bit...
22:26
<bakkot>
Decorators are ultimately about targeted/declarative meta-programming. Without them we'd have no way to ergonomically metaprogram over class fields (and before accessor no way at all). Is it not in scope to metaprogram in a similar way over parameters?
It's "in scope" in the sense that you can argue for it, certainly? But I don't think it's "in scope" in the sense that having one implies we must have the other.
22:26
<ljharb>
also "metaprogramming is desirable" isn't necessarily a universal belief
22:27
<justinfagnani>
talk about ships that sailed in JS though
22:27
<bakkot>
the eval ship sailed too but like
22:27
<bakkot>
we don't need to add more eval
22:27
<ljharb>
that we've allowed one form of a capability does not mean we should open the floodgates
22:28
<shu>
i don't even like DSLs!
22:28
<rbuckton>
I think bakkot's point is also spot on. Java has an overuse of classes for everything, and this is shoehorning a bunch into functionality into classes because we want it to be class method param decorators
I haven't really seen this in 8 years of this feature in TS. It may happen, but certainly not frequently.
22:28
<shu>
i have been radicalized despite my PL and compilers upbringing
22:28
<justinfagnani>
this isn't eval, or close. But metaprogramming in JS is as fundamental as the object model, 'x' in o, o[x], for (k in o) etc
22:29
<shu>
what do you mean by metaprogramming? those constructs you listed are not metaprogramming
22:29
<ljharb>
overuse of classes? i've seen that in plenty of JS/TS codebases
22:29
<shu>
at least not in my head
22:29
<justinfagnani>
i don't even like DSLs!
tagged template literals sailed too!
22:29
<bakkot>
I haven't really seen this in 8 years of this feature in TS. It may happen, but certainly not frequently.
Isn't the BooksAPI example a really clear example of that?
22:29
<bakkot>
There's no reason to make that a class at all except that it's the only way you can get parameter decorators
22:29
<Justin Ridgewell>
I think the code samples in the slides demonstrated it already?
22:29
<bakkot>
In any other context those functions would be separate functions
22:30
<rbuckton>
Only in that it is a fairly limited example. NestJs has better examples. These often are decorated at the class level as well.
22:30
<shu>
tagged template literals sailed too!
the ability to embed a language between some quotes isn't also the same treatment that languages that care about DSLs give to DSLs. agreed in the abstract but pretty different in degree imo
22:30
<justinfagnani>
what do you mean by metaprogramming? those constructs you listed are not metaprogramming
being able to introspect objects and dynamically manipulate them is in the realm of metaprogramming for many languages where objects aren't maps. In other languages doing that would specifically require using a reflection API.
22:30
<littledan>
Sorry for causing delay!
22:31
<shu>
i see that as reflection
22:31
<shu>
when i say metaprogramming i specifically mean reflecting code as data that can be manipulated
22:31
<shu>
if you are reflecting data as data, i don't consider that metaprogramming
22:31
<shu>
somewhat confusingly, you sometimes hear this referred to as "homoiconicity" from the schemers
22:32
<littledan>
I've had other proposals fail to advance explicitly because of a lack of sufficient real world examples, so I may have overcorrected a bit...
I really appreciated all the examples, especially how you showed how people really want to use class parameter decorators, and didn't just focus on the ones that would look best to committee. (And we did hear, today as well, that one convincing example was not enough for AsyncContext.)
22:33
<littledan>
if you are reflecting data as data, i don't consider that metaprogramming
I think it's reasonable to consider object field names "code"
22:33
<shu>
disagree
22:33
<shu>
i don't think it's reasonable to consider strings code?
22:33
<ljharb>
i also disagree
22:34
<littledan>
I mean, they are code in other languages
22:34
<shu>
what does that mean?
22:34
<shu>
you can jump to a string?
22:34
<littledan>
well, just accessing a field by name in C++ is a fragment of code, and the kind of stuff you can do with [] in JS would be "reflection"
22:35
<shu>
i am very confused
22:35
<littledan>
anyway this is philosophy and not relevant to any decision we have here
22:35
<ptomato>

I guess in that there is no way to do this in C++?

struct S {
  int a;
  int b;
};
S* s = new S();
const char *fieldname = "a";
s->[fieldname] = 5;
22:36
<justinfagnani>
in many languages a utility to replace a method would have to use metaprogramming, in JS you can patch a prototype - same goal, different mechanism. I think it's still metaprogramming.
22:36
<shu>
okay, then my apologies for using too imprecise a term
22:36
<littledan>

I guess in that there is no way to do this in C++?

struct S {
  int a;
  int b;
};
S* s = new S();
const char *fieldname = "a";
s->[fieldname] = 5;
exactly, whereas you can do this with some kind of Java "reflection" API I think
22:37
<shu>
i am specifically against evolving JS to enable more facilities to reflect code as data in order to manipulate that data, and to evaluate the manipulated new data as code
22:37
<shu>
a space that i consider decorators to be in generally, thus the desire to restrict them
22:37
<ptomato>
although, now that I think of it, you can do it in C++ with offsetof and/or template parameters
22:38
<justinfagnani>

and to evaluate the manipulated new data as code

this isn't part of the proposals though, right?

22:38
<apaprocki>
although, now that I think of it, you can do it in C++ with offsetof and/or template parameters
or using a map from string -> pointer
22:38
<bakkot>
justinfagnani: e.g. the proposal in its current form exposes the names of parameters, which thus far are purely code rather than data except in terms of f.p.toString
22:38
<shu>

and to evaluate the manipulated new data as code

this isn't part of the proposals though, right?

not anymore it isn't, the bag of descriptors thing kinda had that feel
22:38
<justinfagnani>
if it helps to use "reflection" instead of "metaprogramming", to indicate there are no new facilities for evaluating data as code, then ok
22:39
<ljharb>
code as data?
22:40
<shu>
justinfagnani: e.g. the proposal in its current form exposes the names of parameters, which thus far are purely code rather than data except in terms of f.p.toString
precisely this. currently you can alpha-convert (or de bruijn index-ize) parameters, if there's no presence of direct eval
22:40
<shu>
decorators prevents this
22:40
<justinfagnani>
I meant "data as code" referring to Shu's objection
22:40
<shu>
i think jordan is just saying you reversed the direction
22:40
<justinfagnani>
I did?
22:41
<justinfagnani>
you oppose reflecting on code as data, then using evaluating that data as new code
22:41
<ljharb>
"evaluating code as data" is the Bad Thing
22:41
<justinfagnani>
yes?
22:41
<shu>
oh sure, yes, there's a round trip
22:41
<justinfagnani>
right
22:42
<ljharb>
"evaluating data as code" is already eval, and separately we also want to avoid new forms of eval
22:42
<shu>
so thanks for pushing on this i guess i don't strictly mean a full round trip
22:42
<shu>
reifying code as data, then running code on that code-as-data and causing new behavior, also feels like a smell to me
22:43
<shu>
that's how i think of what underlies people not liking "hidden magic"
22:44
<bakkot>
yes for DI in particular
22:44
<bakkot>
like normally the answer to "how did these values get bound to these parameters" is "the caller passed them in, or they are the default values"
22:44
<bakkot>
after parameter decorators, the answer will be "it is literally not knowable'
22:45
<justinfagnani>
I don't use DI myself, but... this is also true in DI
22:45
<justinfagnani>
the DI container passes in the parameters through a normal ctor call
22:45
<ptomato>
I think of hidden magic much more broadly - for me it's anything where execution jumps to an entirely different place and it's not obvious from the code
22:45
<ptomato>
like accessor properties, operator overloading, ...
22:46
<bakkot>
the DI container is a maximally abstract central location for passing values to things
22:46
<bakkot>
"the values are passed by the DI container" doesn't tell you anything about how they got there
22:47
<bakkot>
similarly, if you (as I do) transform your whole program into a bespoke implemented-in-JS VM, and then the main loop of the VM does the dispatch for all function calls in the entire program, that's also "the values are passed by the callers" but it's completely impossible for readers to follow
22:47
<ptomato>
I don't necessarily want to stamp out hidden magic, I think it's great when used responsibly and in reasonable amounts, and I'd hesitate to pass a value judgement on others' codebases that might have different tradeoffs as to what they consider "reasonable"
22:47
<justinfagnani>
it's fine to not like that, but it's pretty analogous to higher-order-functions... those can absolutely be abused in nasty ways. So many of us would prefer code bases that don't do that too much. But is it invalid as a whole?
22:48
<ptomato>
haha, I think I'm saying the same thing as justinfagnani here :-)
22:48
<bakkot>
I don't know what "invalid" means.
22:48
<bakkot>
Like it does... work? It's a legal program you can write in a language which allows it?
22:48
<bakkot>
But is it something the language should specifically set out to enable? That is a matter of opinion and my opinion is no, it should not.
22:48
<ljharb>
i feel like there was not appetite to add "curry" or "compose", partially for those reasons
22:53
<shu>
man if my Schemer professors could see me now
22:53
<shu>
"macros are bad, actually" "language tower is dumb, actually"
22:54
<Michael Ficarra>
I also reviewed this proposal (aside from the latest grammar changes)
22:54
<bakkot>
do you mean numeric tower or does "language tower" mean a different thing?
22:54
<shu>
no i mean language tower
22:55
<shu>
trying to find some documentation here...
22:55
<Michael Ficarra>
in Scheme, in order to solve any problem, you first create the perfect language for solving that problem, and then you write the solution in that language
22:56
<shu>
but yes, the basic idea is you build a tower of DSLs that bottoms out at Core Scheme or whatever
22:56
<Michael Ficarra>
DSLs on DSLs
22:56
<shu>
and hygenic macros pave the way for this wonderful write-only worldview
22:56
<shu>
heaven forbid you should want to collaborate with others
22:57
<Michael Ficarra>
that's why schemers value PL skills so highly, it's because they see every programmer as a PL designer
22:57
<bakkot>

https://softpanorama.org/People/Knuth/index.shtml#Introduction

As to your real question, the idea of immediate compilation and "unit tests" appeals to me only rarely, when I'm feeling my way in a totally unknown environment and need feedback about what works and what doesn't. Otherwise, lots of time is wasted on activities that I simply never need to perform or even think about. Nothing needs to be "mocked up." ~knuth

23:00
<Michael Ficarra>
something we haven't done as well on: D&I initiatives
23:00
<shu>
please photoshop me into the photo
23:06
<shu>
you can use this picture
23:06
<apaprocki>
thought it would be your router with the blinking connection light
23:09
<rbuckton>
i don't think it's reasonable to consider strings code?
Python considers parameter names to be __code__, if that helps.
23:13
<Chris de Almeida>
🎉
23:16
<waldemar>

I guess in that there is no way to do this in C++?

struct S {
  int a;
  int b;
};
S* s = new S();
const char *fieldname = "a";
s->[fieldname] = 5;
Without using macros there is no way I can think of to use the field names as string keys. But I've seen dark template magic that lets you take a class such as S and do generic introspection about its fields and their types, iterate through the fields, get the nth field and its type, etc.
23:33
<ptomato>
For sure. After I posted the message, I thought of `offsetof`