15:14
<Rob Palmer>
Hello all. Plenary meeting begins in just under two hours. For those attending in person in Seattle, please arrive from 09:20 where you will be met in the F5 lobby. Breakfast will be served on the same floor as the meeting room from 09:30.
15:33
<shu>
i still don't see a zoom link
15:43
<Rob Palmer>
The entry-form containing the zoom link will be posted in the next 30 mins and I will notify here.
16:20
<Jack Works>
why we're always changing the meeting software 🤔
16:21
<Rob Palmer>
The entry form is now available on the Reflector: https://github.com/tc39/Reflector/issues/461
16:22
<Rob Palmer>
Jack Works: This is due to host room setup. The room has been built to work with Zoom, e.g. the AV is connected to an inaccessible Zoom server. We did try to get Google Meet running with no success.
16:55
<Rob Palmer>
We begin in 5 minutes!
16:56
<Rob Palmer>
This is our room for the week.
16:59
<ryzokuken>
looks great!
17:02
<shu>
Customer Engagement Center
17:04
<yulia>
looks really fancy
17:04
<yulia>
(im not present in any form today)
17:09
<Anthony Bullard>
Wish I was there
17:14
<msaboff>
@bakkot You should probably advertise somehow that you are recording for the late arrivals.
17:25
<bakkot>
msaboff: I'll say it again in my editor update
18:09
<shu>
dminor: not sure i understand that point. that sounds like mozilla-internal meeting wrangling
18:09
<ryzokuken>
I think the point they tried to make was that what Shane's mentioning now
18:09
<ryzokuken>
TG2 is run very differently
18:10
<ryzokuken>
for one, the agenda isn't set up clearly ahead of time
18:10
<ryzokuken>
we don't use TCQ but do use a simpler Google Meet queue
18:10
<shu>
ah i misunderstood then, it was about how TG2 is run, not mozilla?
18:11
<ryzokuken>
well, a bit of both I thought
18:11
<ryzokuken>
because of how TG2 is run, Mozilla cannot have structured internal discussions about the agenda a week ahead
18:11
<ryzokuken>
(IIUC, dminor will probably correct me)
18:11
<dminor>
Basically, it would be difficult for us to review proposals properly in advance given the way that TG2 is currently run, so we'd prefer to continue to do advancement in the main committee meetings
18:12
<shu>
dminor: okay, thanks
18:15
<littledan>
Async: Please share the link to the slides on test262 funding so we can reference them from the notes.
18:25
<Ashley Claymore>
https://ptomato.name/talks/tc39-2023-03/
18:25
<Ashley Claymore>
agenda and notes updated
18:28
<Rob Palmer>
To meet Justin Grant's schedule constraint, we are suggesting Temporal will be at 13:00 (first thing after lunch)
18:31
<shu>
wow jordan sounds great
18:31
<shu>
kudos to these room mics
18:31
<apaprocki>
Do any other Ecma TCs have shared costs between member companies that attend? Curious if something like specific TC "dues" could work if rolled up into the yearly fee.
18:32
<apaprocki>
A lot of pain in companies contracting out work if they can't do it themselves is the burden of that internal process...
18:35
<ljharb>
it definitely seems like the primary purpose of member dues is so Ecma, not individual members, can fund shared needs.
18:59
<HE Shi-Jun>
not sure how renaming to limit/skip solve the problem ...
19:00
<Bradford Smith>
do all of the iterator helpers currently close the underlying iterator?
19:00
<rbuckton>
not sure how renaming to limit/skip solve the problem ...
I don't think it does, especially given the rather common meaning of take across the ecosystem as well as other languages.
19:01
<littledan>
Do any other Ecma TCs have shared costs between member companies that attend? Curious if something like specific TC "dues" could work if rolled up into the yearly fee.
Ecma folks have told me that there have been shared costs historically, and that members handle their own financial things when it comes up
19:01
<rbuckton>
It's rather trivial to write a wrapper for an iterator that doesn't forward return
19:01
<littledan>
(and they consider this best practice in general)
19:01
<Rob Palmer>
We will return in one hour. If any of the remote attendees have feedback on AV etc please say it here.
19:01
<Bradford Smith>
I find "limit" less understandable than "take". If it helps avoid misunderstanding, I would expect that's only because one has to read the docs to understand what it does at all.
19:10
<peetk>
imo "limit" conveys very clearly that the iterator is closed, i guess because it sounds like SQL limit, and obviously SQL queries are not stateful; whereas "take" is much more ambiguous. but i guess this is a minority view!
19:56
<Bradford Smith>
Are there actually any iterator helpers in the proposal that do not close the underlying iterator?
19:58
<Justin Ridgewell>
They all either iterate everything (thus closing the underlying), or close when they early exit
19:58
<bakkot>
take is special in that take ends before exhausting the underlying iterator
19:58
<Bradford Smith>
My general expectation is that if I pass an iterator off to any other code, I should assume it is exhausted and not touch it again myself.
19:59
<bakkot>
whereas if you map or something the expectation is that it either you are exhausting it, which will naturally close the underlying iterator, or closing the map helper explicitly
20:00
<Justin Ridgewell>
take is special in that take ends before exhausting the underlying iterator
So does some, every, and find
20:00
<bakkot>
Justin Ridgewell: those don't produce new iterators though
20:00
<rbuckton>
Caveat being that some, every, and find return scalar results
20:00
<bakkot>
they are as it were "consumers" rather than "transfomers"
20:01
<rbuckton>
Though take ending before exhausting the iterator is a misconception. The fact it calls return is more of an optimization than a meaningful difference when it comes to sequence operators.
20:02
<bakkot>
by "an optimization", do you mean relative to the option of manually exhausting the underlying by calling .next repeatedly, or something else?
20:03
<rbuckton>
Yes.
20:03
<rbuckton>
If JS had no .return and the only way to close an iterator were to exhaust it, I would expect take to exhaust the iterator.
20:04
<rbuckton>
So its good that return exists, as it allows us to short-circuit such an expensive operation.
20:05
<rbuckton>
But I'm pretty sure that in every example of prior art in the ecosystem, where take is used it means "take X items and exhaust/close the underlying iterator"
20:05
<rbuckton>
If the iterator were backed by a database, I would expect take to close the connection when completed.
20:05
<rbuckton>
The alternative is resource starvation, which is a bad failure state.
20:06
<rbuckton>
If you want "consume X and not close", that operation is normally named something like read (at least, where IO is concerned)
20:10
<ljharb>
erights: i finished the iterator helpers "close the underlying iterator" change before lunch, and it passes all the proposed test262 tests as well as my own
20:13
<Rob Palmer>
We are bringing forward Async Explicit Resource Management to happen this afternoon. TCQ and draft schedule are updated accordinlgly.
20:15
<Richard Gibson>
rbuckton: isn't your claim about taking more being uncommon directly contradicted by the issue that prompted this discussion?
20:16
<rbuckton>
My impression is that the use case in that issue was a misuse of the API. Perhaps take may seem confusing in a vacuum, but not with adequate context
20:19
<littledan>
Why is it "Speaker's summary of key points" rather than "summary of key points" in the notes?
20:19
<Luca Casonato>
Didn't get to it due to time, but there is precedence for a preventClose/preventReturn option on the web: preventClose on ReadableStream.prototype.pipeTo and ReadableStream.prototype.pipeThrough. I am not necessarily in favour of adding that - but if we did, people may already be familiar with the opt out behaviour.
20:19
<littledan>
Why is it "Speaker's summary of key points" rather than "summary of key points" in the notes?
I haven't really been seeing speakers fill this in; I think note-takers and the committee could fill it in as well
20:21
<Rob Palmer>
It can be written by anyone so please change the title if you like. The key is that the presenter ought to be at least approving the summary so that we have some kind of responsibility when distributing the load of writing these summaries.
20:21
<rbuckton>
The confusion is a consequence of choosing to build an API that is dependent on Iterator vs the notion of an iterable. As I understood it as the proposal was advancing, basing this on iterator meant we were in the realm of "one shot" or "single use" iterators, and that any kind of reusable iteration would rely on arrow functions. IIRC, all of the helper methods are exhaustive, either through repeated calls to .next or through the use of .return. I don't believe .take should be substantially different in this regard. I would much rather have an "opt-out" mechanism to avoid closing an iterator than breaking from the norm here.
20:24
<bakkot>
Definitely agreed that take not exhausting is not an option
20:24
<bakkot>
the question was just whether a different name could lead people to correctly intuit the semantics
20:25
<shu>
my intuition is no, unless the name is literally, like takeAndThenClose
20:32
<rbuckton>
The alternative, .limit, only really makes sense for numeric arguments. It becomes much less clear if you later adopt something like .limitWhile (vs. .takeWhile).
20:33
<bakkot>
fun fact, Java has both limit and takeWhile
20:34
<bakkot>
(and no take)
20:36
<apaprocki>
64+32 Abseil: https://github.com/abseil/abseil-cpp/blob/master/absl/time/duration.cc#L15-L50
20:37
<rbuckton>
Didn't get to it due to time, but there is precedence for a preventClose/preventReturn option on the web: preventClose on ReadableStream.prototype.pipeTo and ReadableStream.prototype.pipeThrough. I am not necessarily in favour of adding that - but if we did, people may already be familiar with the opt out behaviour.
I know that NodeJS has that concept, i.e.stream.pipeline(streams, { end: true }) https://nodejs.org/dist/latest-v19.x/docs/api/stream.html#streampipelinestreams-options
20:38
<rbuckton>
and readable.pipe(dest, { end: true }). I'm not sure about the DOM APIs offhand
20:39
<Luca Casonato>
for DOM it'd be readable.pipeTo(writable, { preventClose: true })
20:39
<rbuckton>
Yeah, I misread your comment as a question, sorry.
20:49
<shu>
waldemar: the core confusion from me is why do you trust multiple implementations to be correct and interoperable here, if you don't trust the spec to be correct (because it's so tricky to get correct)?
20:49
<shu>
like my goal isn't just a correct document, it's correct interopable implementations
20:52
<waldemar>
shu: It sounds like you're trying to fit the spec around one possible (and pretty problematic) implementation. The spec should be implementation-agnostic about internal details.
20:53
<shu>
in this case my understanding is that the bounds the champions are working to put in place are precisely so that it is implementable with that technique
20:53
<waldemar>
I'm also more interested in the ns vs µs question.
20:53
<shu>
(also why is the 64+32 impl problematic?)
20:54
<littledan>
I'm also more interested in the ns vs µs question.
I know that ptomato framed this as "for future discussion" but I don't see any arguments to switch to microseconds at this point.
20:54
<waldemar>
Elementary math: 64+32 can implement integral counts of subseconds. This is obvious.
20:55
<shu>
well, V8's position is still pro microseconds, but we won't block the proposal on it if implementation complexities and bad performance cliffs are addressed
20:55
<waldemar>
Not obvious: spec that explicitly manages two integers implements integral counts of subseconds. It's easy to get carries and overflows wrong, and you can't tell without examining the entire spec.
20:55
<shu>
i agree with you
20:56
<shu>
what i don't get is, why do you think that trickiness is best left for implementations to all figure out via implication?
20:56
<waldemar>
If you just want µs, then you can store durations in flat 64-bit integers and get a much more efficient implementation with a range of >500,000 years.
20:56
<shu>
indeed! i just want us
20:56
<shu>
but v8 has not been able to convince the champion group
20:57
<littledan>
If you just want µs, then you can store durations in flat 64-bit integers and get a much more efficient implementation with a range of >500,000 years.
Do we have any information that this difference in performance will be signficant? there's so much other stuff going on anyway
20:58
<shu>
it's a nuanced conversation that's hard to tease apart
20:58
<shu>
it's not just absolute performance, it's the complexity around supporting optimized paths also
20:58
<shu>
it's philosophical objection
20:58
<waldemar>
Whether a difference in performance is significant depends on who is writing the benchmark ☺
20:59
<shu>
apaprocki has given examples of other systems that support ns that temporal might want to interface with, which i don't really get at all
20:59
<apaprocki>
ns are common enough nowadays that it seems it would be limiting use cases unnecessarily by limiting to µs, e.g. node embeds v8 and would hopefully like to represent filesystem times without losing precision
20:59
<shu>
those other systems don't have ns as part of a date-time arithmetic library, they're raw ns counts
20:59
<shu>
they're int64s
20:59
<shu>
what i'm saying is it doesn't follow "ns are common enough -> ns need ot be supported in a fully featured date-time arithmetic library"
21:00
<shu>
you still can just put the raw ns count into a BigInt
21:02
<shu>

V8 position is:

  • ideal: us precision, simple bounded arithmetic + storage follows straightforwardly
  • can live with: ns precision, with 64+32 being a tried-and-proven implementation technique from e.g. abseil that we can use
  • cannot live with: ns precision, bigint math required
21:02
<apaprocki>
what i'm saying is it doesn't follow "ns are common enough -> ns need ot be supported in a fully featured date-time arithmetic library"
well, take filesystem times.. certainly those are displayed on screens as formatted date times and not counts
21:02
<shu>
great, it's fine to format them
21:03
<shu>
you need to do full arithmetic to ns precision?
21:03
<shu>
how is that useful?
21:06
<littledan>
I haven't found this as a hard requirement for us when I talked to the relevant groups inside of Bloomberg (except for certain algorithms like PTP which we probably wouldn't end up porting to JS)
21:08
<apaprocki>
there are certain feeds of information where the individual events are represented in ns precision and series of events could be displayed as offsets from an initial event (in essence, durations from an arbitrary epoch rather than UTC epoch)
21:10
<littledan>
I think using us would create somewhat of a risk, that Temporal might become obsolete (which is a surprising choice given how much else we decided to be super future-proof for). It's sort of clear that we don't really need to go more precise than ns.
21:10
<littledan>
(and a later evolution here would be really bad, given compat/interop risks)
21:12
<littledan>
yes (edited)
21:15
<littledan>
Good news everyone: The transcriptionist might be available for tomorrow!
21:15
<littledan>
(they got back to me by email)
21:28
<bakkot>
this isn't worth bringing up, but await is not reserved in strict mode, only in module code and async functions
21:28
<Michael Ficarra>
very very few people are aware of syntax being dependent on the start symbol
21:29
<ljharb>
bakkot: perhaps we should have Set.prototype.sort if the sort order is important?
21:30
<Michael Ficarra>
if you're going to explicitly manage the sort order, put it in an explicitly ordered container
21:30
<bakkot>
the problem is that when I care about the order it's because I care about insertion order specifically
21:30
<bakkot>
and you can't sort it into "insertion order"
21:32
<ljharb>
ah true, hm
21:35
<Michael Ficarra>
I know we don't have much else to go on, but I feel like we're taking these poll results way too seriously
21:35
<bakkot>
right now we're just hearing what they are
21:35
<bakkot>
no one has expressed anything about what to do with them
21:41
<Michael Ficarra>
for await has always felt like an awkward piece of syntax to me, though
21:41
<Michael Ficarra>
like I don't know if we should be using it to guide future syntax choices
21:44
<bakkot>
tbf if we're just picking something because we have to pick something, "difficulty of parsing" is a fine reason to choose - I just wouldn't want "difficulty of parsing" to prevent us from picking a thing we do all think is best
21:44
<littledan>
for await has always felt like an awkward piece of syntax to me, though
huh? it seems intuitive to me
21:46
<justinfagnani>
as a code reader, I kind of want a syntactic note on the block that it may await at the end, not just on individual statements in the block
21:46
<justinfagnani>
like async on a function
21:48
<Rob Palmer>
justin, is this just syntax shock? I fully have the same initial reaction as you. I just recall many times when my initial reaction is later overcome once it goes into the language and you get used to it
21:49
<shu>
that's not much of an argument though, because you can make that about literally any syntax we choose?
21:49
<justinfagnani>
could be?
21:49
<shu>
"you'll get used to it"
21:49
<Rob Palmer>
That could be the JS motto.
21:50
<bakkot>
justinfagnani: yeah the original design was more like python's with or java's try-with-resources, which has that
21:50
<bakkot>
but we ultimately decided not that
21:50
<justinfagnani>

Would something like:

async {
   await using x = y;
   foo();
}

make it more clear that the block may yield at the end?

21:50
<justinfagnani>
bakkot: ok
21:50
<Mathieu Hofman>
FYI, Mark is not active on Matrix
21:50
<rbuckton>

Would something like:

async {
   await using x = y;
   foo();
}

make it more clear that the block may yield at the end?

This was something we discussed in depth and resolved in the last meeting
21:50
<justinfagnani>
ok, thanks
22:05
<Chris de Almeida>
so... what just happened?
22:05
<shu>
sorry all didn't mean to make the decision space so complicated
22:05
<littledan>
no this was good
22:05
<littledan>
please read the summary at the bottom of the notes page and edit it or make comments as needed
22:05
<shu>
the only signal i got from the past 10 minutes is, the consensus was not just "we can all live with await using" but in fact "we are now convinced await using is the ideal, if achieveable"
22:05
<shu>
which is a good signal
22:05
<shu>
and backs up coming back next meeting
22:06
<rbuckton>
Having a block-level indicator was the issue blocking the async version using for the past few years.
22:06
<Chris de Almeida>
yes -- maybe we should ask for consensus on that summary conclusion.. I'm concerned we are not all on the same page
22:06
<littledan>
the only signal i got from the past 10 minutes is, the consensus was not just "we can all live with await using" but in fact "we are now convinced await using is the ideal, if achieveable"
Yes, I think await using has broad support (and this is why I wanted to do a temperature check)
22:06
<littledan>
yes -- maybe we should ask for consensus on that summary conclusion.. I'm concerned we are not all on the same page
could you elaborate?
22:06
<littledan>
(I did ask everyone to review it, but we can come back and project it to force everyone to review it when we come back from the break)
22:07
<shu>
littledan: heh, i still don't like it! but i'm fine with it
22:08
<Chris de Almeida>
what's there atm makes sense to me -- just want to confirm expectations as it seemed we might have been going a different direction for a bit there
22:21
<shu>
i have lost my apartment internet due to what i assume is high winds in SF currently
22:21
<shu>
i don't have good enough cell service to do zoom, so looks like i am out for the remainder of today :/
22:26
<shu>
wait maybe i have enough phone tether to do zoom
22:26
<shu>
it's like 90% packet loss
22:27
<apaprocki>
do you live in a dirigible?
22:27
<shu>
it's called san francisco, thank you
22:28
<sffc>
Frank Tang also said he's been in and out of power/internet
22:32
<littledan>

BTW here are my conclusion notes for the await using topic, please edit in the notes if you want to make changes:

Summary

Various grammars for async resource disposal were considered, including results from polls. The champion's preference became await using, and several delegates were swayed to prefer this option based on the data and arguments presented.
There are concerns about the parse-ability of await using, both based on practical implementations and the fit into the ES spec's cover grammars; it's unclear if certain edge cases will be easy to manage.
If await using isn't viable, it's likely that async using isn't viable, and the committee may come back to the conclusion of using await, but this will need to come back to plenary for future discussion.

Conclusion

The committee resolves to attempt the syntax await using.
The grammar will need to be worked out in a PR, which will need to be presented in a future plenary for review and consensus.

22:44
<shu>
i am triggered about static private semantics
22:44
<Chris de Almeida>
same
22:44
<bakkot>
static private semantics are actually fine
22:45
<bakkot>
the problem is that class extends implies inheritance not just of instances but of the constructors themselves, which is wack
22:46
<littledan>
the problem is that class extends implies inheritance not just of instances but of the constructors themselves, which is wack
I'm like 80% sure I agree. Constructor inheritance is definitely used.
22:46
<bakkot>
yeah I use it myself
22:47
<bakkot>
but it should never have existed, it gives us the wild things like Promise.resolve not working unless bound (whereas Array.from does, for... reasons)
22:54
<Michael Ficarra>
we really need to figure out a more appropriate organisational scheme for well-known symbols than putting them all on Symbol
22:55
<Michael Ficarra>
I don't blame this proposal author for this choice, since we don't have committee guidance on the topic
22:56
<littledan>
we really need to figure out a more appropriate organisational scheme for well-known symbols than putting them all on Symbol
I don't really see the same issue; it's just a single namespace for these things, just like if we had called it __metadata__
22:58
<Michael Ficarra>
littledan: yes, a single global namespace for everything is bad, whether that is globalThis or Symbol
22:58
<danielrosenwasser>
Hey all, Ron (rbuckton ) and I will be requesting a new agenda item this Thursday which will propose the preferred await using syntax for the Async Explicit Resource Management proposal. We're currently working on the grammar, but will let everyone know when the slides and changes are ready to review.
22:58
<Michael Ficarra>
ironically, that opinion is also on-topic for this topic
22:59
<shu>
i don't think a single global namespace is bad
23:00
<shu>
i think it's only ex ante bad but is mostly ok
23:01
<Chris de Almeida>
var doNotPolluteTheGlobalNamespace = {};
23:02
<littledan>
Option 3 feels the most bizarre to me, since the intended usage of it needs to go back to the single namespace anyway
23:02
<Michael Ficarra>
shu: surely with time, we will have more than 1 built-in protocol that want to use the same simple name for one of their provided/required fields
23:03
<shu>
that's why i said ex ante bad
23:03
<Michael Ficarra>
none of these well-known symbols have particularly unique simple names
23:03
<shu>
my point is that when we come to that bridge it's usually not a big deal to work around
23:04
<Michael Ficarra>
shu: fair, though it would be nice to set a precedent for userland protocols, especially if we ever have a world with first-class protocols
23:06
<Ashley Claymore>
which class does the metadata get added to? If there was a class decorator which returns a new class, does that get it, or should it have to make sure it 'forwards' on `Symbol.metadata' ?
23:06
<rbuckton>
The final class
23:07
<rbuckton>
(I think)
23:07
<Ashley Claymore>
so might not work if the decorator freezes the class?
23:07
<rbuckton>
A good class decorator that performs replacement should either subclass with extends, or use .setPrototypeOf to emulate that approach, unless it is doing something very complex.
23:09
<ljharb>
either, or what?
23:10
<Ashley Claymore>
so Symbol.metadata would already be there on the class that is being decorated? Rather than added to the final class?
23:11
<rbuckton>
I'd have to recheck the spec
23:13
<shu>
i'm confused about kevin's use case
23:14
<bakkot>
two libraries which both want to use the key type
23:14
<bakkot>
including possibly two major versions of the same library
23:14
<bakkot>
you fundamentally cannot use these things at the same time
23:15
<bakkot>
because it's a shared global namespace
23:15
<shu>
is he saying programs will want multiple versions of the same decorator library in the same running app...?
23:15
<bakkot>
multiple versions of a library in the same app is a thing which happens constantly
23:16
<Luca Casonato>
rbuckton: if you want a shared global namespace in scripts, use globalThis? why do we need to add a second global namespace? if you really want a global namespace, there already is one already
23:17
<littledan>
multiple versions of a library in the same app is a thing which happens constantly
right, I guess the question is: are we more likely to want them to share or partition the namespace? I think share is more pragmatic, given the cases we've heard about. What's more likely to work in practice?
23:17
<shu>
but... why is the app use two major versions of the same library in the same app? that happens?
23:17
<bakkot>
that happens constantly
23:17
<bakkot>
littledan: they can't share
23:17
<rbuckton>
rbuckton: if you want a shared global namespace in scripts, use globalThis? why do we need to add a second global namespace? if you really want a global namespace, there already is one already
That is essentially what reflect-metadata does, and one of the things we have sorely wanted to address with this proposal.
23:17
<bakkot>
like, that's the problem
23:17
<bakkot>
they use the same key
23:17
<shu>
it happens constantly?
23:17
<rbuckton>
We cannot mutate globalThis in a locked down environment like SES
23:17
<bakkot>
and coordinating it becomes the consumer's problem
23:17
<Jesse (TC39)>
the various layers of dependency hell
23:18
<littledan>
littledan: they can't share
I don't see why this is such an absolute, rather than pragmatic, thing
23:18
<shu>
okay i think i'm getting the picture. currently the builders do some kind of deduplication / versioning at the build step for regular import/exports
23:18
<rbuckton>
Also, [Symbol.metadata] isn't necessarily a "global namespace" any more than a static property on the class is a global namespace. Because the [Symbol.metadata] property is a static property on a class.
23:19
<bakkot>
rbuckton: right, class fields are also a shared namespace, which is why string-named mixins was not a viable proposal
23:19
<littledan>
Symbol-named protocols are also not beyond Stage 1; I still like string-named mixins.
23:20
<rbuckton>
There's a difference between "shared namespace" and "global namespace" though. The 2nd term has more implications
23:20
<bakkot>
the names of all fields used in all decorators anywhere must be unique
23:20
<bakkot>
that's global
23:20
<rbuckton>
I want a mutable object because I don't want a shared global namespace.
23:21
<rbuckton>
The alternative to use globalThis mandates I do the worse thing
23:21
<bakkot>
rbuckton: but only you
23:21
<Michael Ficarra>
"be careful" assumes that all parties are coordinating, but in reality, pages and applications are often composed of many non-coordinating scripts
23:21
<bakkot>
I am OK with only typescript having to do the worse thing
23:21
<bakkot>
as long as everyone else falls into the happy path of the right thing
23:21
<rbuckton>
Its not only typescript, its every typescript user.
23:22
<ljharb>
TS users presumably would only use an interface TS provides, regardless of which option was chosen?
23:22
<littledan>
"be careful" assumes that all parties are coordinating, but in reality, pages and applications are often composed of many non-coordinating scripts
You only have to worry about the set of decorators that a particular class uses.
23:23
<Michael Ficarra>
littledan: and are those decorators always created by a single party or by coordinating parties? I doubt it
23:23
<nicolo-ribaudo>
You only have to worry about the set of decorators that a particular class uses.
Decorators from different libraries can usually be mixed, so the decorator author doesn't really know what this set is
23:24
<littledan>
Decorators from different libraries can usually be mixed, so the decorator author doesn't really know what this set is
I don't think this is really true with framework decorators
23:24
<Michael Ficarra>
littledan: "not true for some cases" is not the bar we're trying to meet here
23:24
<bakkot>
ljharb: re: your queue item, the only reason I suggested a frozen object instead of a symbol is that a frozen object lets you get to the parent metadata
23:25
<ljharb>
makes sense, thanks
23:27
<rbuckton>
Symbol.for("foo") isn't much better than "foo"
23:27
<bakkot>
I didn't mention this, but the other downside of option 1 is that it is public-by-default, which is... very bad
23:27
<bakkot>
you can remember to be disciplined about it but people will not remember
23:27
<littledan>
I didn't mention this, but the other downside of option 1 is that it is public-by-default, which is... very bad
It's not anything by default; it's just as easy to use the WeakMap with it
23:27
<bakkot>
no it isn't
23:27
<rbuckton>
I didn't mention this, but the other downside of option 1 is that it is public-by-default, which is... very bad
There is no default. Its purely based on usage.
23:28
<bakkot>
it is not as a easy to use a weakmap as it is to use a string-named property
23:28
<rbuckton>
But option 2 has the same level of difficulty with weakmaps
23:28
<bakkot>
yes but that's the only way to use it, so that's fine
23:29
<bakkot>
like, as a practical matter, people are going to use public string-named properties with option 1, even when they don't intend to make a public API
23:29
<bakkot>
that is what is going to happen
23:29
<bakkot>
that is what "public-by-default" means
23:31
<rbuckton>
That is more about documentation and learning than it is about capability. If you tell folks, use WeakMap or Symbol if you're concerned about collisions, but strings or Symbol.for if you're not. Library authors will almost certainly avoid collisions, end user applications often won't need to.
23:31
<bakkot>
You have a lot more faith in the power of documentation to shape what happens than I do
23:31
<bakkot>
for that matter you also have more faith in the power to shape documentation
23:31
<rbuckton>
Assignments to context.metadata will never be so simple as context.metadata["a"] = b anyways
23:32
<littledan>
I really appreciate you being flexible here, bakkot ljharb Michael Ficarra . It's great that we're able to move forward and not have a big gap of metadata-less decorators
23:32
<rbuckton>
context.metadata is just an object. If you need to differentiate between a class, or a method, or a field you still have more work to do to avoid collisions, even in the WeakMap case.
23:32
<Justin Ridgewell>
Is the context object (not the context.metadata obj) consistent between all decorator invocations on a particular class?
23:32
<Justin Ridgewell>
Or is it a new object for every invocation?
23:33
<rbuckton>
Same object for every decorator on a single class
23:33
<rbuckton>
including the methods and fields.
23:34
<Justin Ridgewell>
If we had chosen Option 2 here, would there even have been a need for context.metadataKey at all?
23:34
<Justin Ridgewell>
We could have just keyed the WeakMap on context
23:34
<rbuckton>
@((_, ctx) => { ctx.metadata["a"] = 1; })
class C {
  @((_, ctx) => { ctx.metadata["b"] = 2; })
  method() {}
}

produces a single object with { a: 1, b: 2 }

23:34
<bakkot>
yeah you need it to be available after decoration time
23:34
<bakkot>
and you don't want to share the context object
23:34
<bakkot>
which has a bunch of decorator-time-only stuff on it
23:34
<Justin Ridgewell>
Ah, ok
23:34
<rbuckton>
sorry, I misread (despite your clarification).
23:34
<rbuckton>
context is not shared, only metadata is.