00:00
<rbuckton>
bakkot: I've run into this when working with non async/await code (i.e., working directly with Promise).
00:00
<snek>
it turned out it was fine
love to hear it
00:01
<Justin Ridgewell>
shu: finally found the example that AMP hit: https://github.com/ampproject/amphtml/pull/15107
00:01
<rbuckton>
A better (but maybe harder to answer) question is, how may people incorrectly write Promise.resolve(f())? This wouldn't fix those cases, but would give those developers something easier to reach for when they're looking for a solution.
00:01
<Justin Ridgewell>
After this, we forced all Promise.resolve(fn()) to use tryResolve(fn) helper
00:02
<shu>
is jest bad
00:02
<shu>
i feel like i've picked up some subtext somewhere that jest is bad, but unsure
00:02
<rbuckton>
jest is a good test framework that unfortunately does some very bad things.
00:02
<snek>
i think jest is ok?
00:02
<nicolo-ribaudo>
I feel like I'm the only one in the world that still likes Jest
00:02
<snek>
i don't use it often
00:02
<ryzokuken>
is jest bad
you don't want to open this can of worms in this group
00:03
<nicolo-ribaudo>
Jest does Bad Things ^TM just because we haven't shadow realms yet
00:03
<hax (HE Shi-Jun)>
Promise.resolve((async () => fn())()) ?
00:03
<nicolo-ribaudo>
So Node folks hate it
00:03
<littledan>
only some parts of Jest are bad...
00:03
<snek>
node folks hate everything, i say this as a node folk
00:03
<rbuckton>
Promise.resolve((async () => fn())()) ?
Or just (async () => fn())().
00:05
<nicolo-ribaudo>
I think we should start using more the number of dependents as a metric, rather than the number of downloads, since it tells us how many people actually needed to write that code
00:05
<nicolo-ribaudo>
A very popular library can still have shitty code
00:06
<snek>
i will continue to use whatever number best supports my position
00:06
<nicolo-ribaudo>
i will continue to use whatever number best supports my position
Number of dependencies
00:06
<bakkot>
ljharb: npm apparently doesn't let you fetch more than 10 pages of dependents so this is useless but since I've written it now https://gist.github.com/bakkot/61a9bddb1c88155297f4c6f0880189f6
00:07
<shu>
ljharb: Justin Ridgewell shoot i missed your message before i didn't give consensus if it came before
00:07
<shu>
that diff is convincing enough for me, stage 2 sgtm, if ljharb wanna come back at end of today
00:07
<shu>
but not 2.7 yet because i think it probably needs to pass along ...arguments
00:09
<littledan>
shu: finally found the example that AMP hit: https://github.com/ampproject/amphtml/pull/15107
This one? yeah, huh...
00:09
<shu>
Justin Ridgewell: so wait actually now i'm reading MDN page for play()
00:09
<shu>
it says if it can't play(), a rejected Promise is returned
00:09
<shu>
was the sync throw a Chrome bug or is MDN wrong?
00:10
<Justin Ridgewell>
If I remember correctly, el.play() used to sync return, then it was changed to return a promise, but it can still sync throw.
00:10
<ljharb>
that diff is convincing enough for me, stage 2 sgtm, if ljharb wanna come back at end of today
awesome, thanks. i'll ask about that
00:10
<shu>
https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/play says rejected Promise
00:10
<shu>
okay if the most compelling argument is "sometimes there are bugs and people do the bad thing", i guess that's fine with me
00:10
<shu>
the cost for this is pretty trivial
00:13
<Justin Ridgewell>
shu: https://github.com/ampproject/amphtml/pull/6083#discussion_r87054018
00:13
<Justin Ridgewell>
I asked the exact same thing
00:14
<bakkot>
so zip is product on iterator (in the type-theory sense). sum doesn't really make sense on sync iterators (you can do zip+flat but there's not much reason) but on async iterators sum totally works, as AsyncIterator.merge or race or something like that. I will probably propose that at some point
00:16
<shu>
Justin Ridgewell: cursed that they just changed it, thanks for the knowledge
00:18
<ljharb>
shu: https://github.com/tc39/proposal-promise-try/issues/9 btw for the passing arguments thing
00:19
<shu>
thanks
00:20
<bakkot>
shu: https://github.com/tc39/proposal-promise-try/issues/9 btw for the passing arguments thing
ok wait if you're ok with arrows why not just use (async () => fn())()
00:20
<bakkot>
am I missing something about that
00:20
<ljharb>
i mean i am not personally ok with using syntax here
00:20
<bakkot>
sorry, that was re: your first comment in that thread
00:21
<snek>
Promise.try(() => f(a, b, c))
00:21
<shu>
ok wait if you're ok with arrows why not just use (async () => fn())()
yeah i'm okay with that?
00:21
<shu>
but i mean i'm willing to take other people's words for what forms they want to type
00:21
<ljharb>
"wrapping in an arrow function" is how i spell "wrapping in a function" for people that can't ship that syntax, like myself :-p
00:21
<shu>
no deeper reason than that
00:21
<ljharb>
i think the readability/confusion thing still applies for an AIIFE tho, arrow or no
00:22
<ljharb>
which tbf is an argument in favor of passing arguments
00:22
<littledan>
what if we let prefix ^ be a shorter way to write ()=>? Could make a lot of these arrows shorter. [but it wouldn't scale to the async case]
00:22
<ljharb>
however, this facility of setTimeout (passing args) has proven very confusing for practitioners, so i'm not anxious to repeat it
00:23
<snek>
what if we let prefix ^ be a shorter way to write ()=>? Could make a lot of these arrows shorter. [but it wouldn't scale to the async case]
& &1 in elixir is like (a) => a
00:23
<rbuckton>
however, this facility of setTimeout (passing args) has proven very confusing for practitioners, so i'm not anxious to repeat it
setTimeout is strange because it injects a timeout between the callback and the arguments.
00:23
<nicolo-ribaudo>
however, this facility of setTimeout (passing args) has proven very confusing for practitioners, so i'm not anxious to repeat it

setTimeout is confusing because

  • it also accepts a string
  • it accepts not only the fn and the params, but also the time
00:24
<snek>
i think arrow functions and bind are both better solutions than making everything that takes a callback also accept arguments somewhere
00:24
<jschoi>
https://github.com/tc39/proposal-pipeline-operator/blob/main/README.md#tacit-unary-function-application-syntax would cover this and have +> % mean x => x.
Er, meant to reply to littledan there.
00:24
<TabAtkins>
For setTimeout, there's a potentially noticeable difference between setTimeout(f, 1000, a, b, c) and setTimeout(()=>f(a,b,c), 1000), which is that a/b/c are evaluated eagerly or late.
00:24
<shu>
accepting a string is the way PHP and god intended
00:24
<TabAtkins>
There's no such difference in Promise.try()
00:25
<rbuckton>
& &1 in elixir is like (a) => a
And we already have partial application at stage 1 if we want to make arrows shorter.
00:25
<shu>
what is going on with matrix
00:25
<shu>
i'm seeing like, decoherence
00:26
<Justin Ridgewell>
Explici t support
00:26
<Justin Ridgewell>
Can’t talk
00:26
<snek>
who was i talking to earlier about discord message logs
00:28
<rbuckton>
i think arrow functions and bind are both better solutions than making everything that takes a callback also accept arguments somewhere
What are your thoughts on https://github.com/tc39/proposal-partial-application?
00:28
<snek>
What are your thoughts on https://github.com/tc39/proposal-partial-application?
neutral to slightly negative
00:28
<snek>
i don't write javascript in a super fp heavy way
00:30
<rbuckton>
That's fair. I'm still planning on coming back to that one at some point. I admit it paired far better with F#-style pipelines, but I still think it has value.
00:35
<rbuckton>
Feedback, someone needs to turn off a mic
00:37
<jschoi>
Did I disappear from the queue?
00:38
<Michael Ficarra>
jschoi: refresh
00:38
<rbuckton>
Did I disappear from the queue?
I see you as the next topic on the queue
00:39
<littledan>
isn't it typed differently because it's not representable as an integer?
00:40
<snek>
ye
00:40
<snek>
the best thing is in v8 there's a parameter you have to pass when converting where you explicitly opt into checking for -0 or not
00:41
<snek>
surely no bugs have ever come of this 😄
00:41
<shu>
isn't it typed differently because it's not representable as an integer?
yeah that sounds right
00:41
<hax (HE Shi-Jun)>
I understand the issue of -0, but I don't think it should be considered in Math.sum proposal.
00:42
<Michael Ficarra>
I'd need a stronger argument to convince me to return +0 when passed an empty input
00:42
<shu>
hax (HE Shi-Jun): in which direction?
00:42
<shu>
Michael Ficarra: well it's confusing!
00:42
<ljharb>
wait why wouldn't empty input produce NaN
00:42
<snek>
i'd want to hear from someone who knows how binary64 works on whether its problematic. if it isn't, we should do +0
00:42
<Michael Ficarra>
shu: it toStrings as 0!
00:43
<nicolo-ribaudo>
wait why wouldn't empty input produce NaN
So that sum(...arr) and arr[0] + sum(..arr.splice(1)) do the same thing for non-empty arr :)
00:43
<ljharb>
they wouldn't anyways because of the current slide, right?
00:43
<nicolo-ribaudo>
Oh actually, with Kevin's algorithm this isn't true
00:43
<snek>
let getNegativeZero = () => Math.sum([]) please don't break my code
00:43
<nicolo-ribaudo>
Yeah good point jordan
00:44
<ljharb>
this is IEEE floats, math and real numbers have nothing to do with anything. "the sum of nothing" can be whatever we want
00:44
<nicolo-ribaudo>
this is IEEE floats, math and real numbers have nothing to do with anything. "the sum of nothing" can be whatever we want
Math.sum([]) === 1
00:44
<snek>
like is there maybe some implication if you do Math.sum(Math.sum(x), y)?
00:44
<shu>
I'd need a stronger argument to convince me to return +0 when passed an empty input
i'm hearing you like exploits
00:44
<ljharb>
Math.sum([]) === 1
i mean we can all point to dumb things in JS :-p doesn't mean we have to repeat the mistakes in sumExact
00:44
<snek>
or use it in other random places
00:45
<hax (HE Shi-Jun)>
hax (HE Shi-Jun): in which direction?
I mean I feel -0 issue is irrelevant.
00:45
<snek>
python also implicitly has ints in places tho
00:46
<Michael Ficarra>
i'm hearing you like exploits
this doesn't prevent -0 from flowing to the wrong place intentionally
00:46
<shu>
hax (HE Shi-Jun): i have already said why it's not irrelevant to v8
00:46
<shu>
this doesn't prevent -0 from flowing to the wrong place intentionally
it's about minimizing surface, not eliminating surface
00:46
<Michael Ficarra>
yeah but that's not the surface
00:46
<shu>
manual inlines in the JIT for builtins is a surface
00:47
<nicolo-ribaudo>
i'm hearing you like exploits

I don't find this convincing here because -0 is already in the language, and returing it from a new function just adds more places to be careful by a limited number (in the places where you are inlining this built-in).

And now we are explicitly aware about this -0, it could be even be explicitly called out in the spec by saying why we return it so that implementers don't miss it.

00:47
<nicolo-ribaudo>
Otoh, Jordan's observation made me less storngly in favor of -0
00:47
<Luca Casonato>
Me too Kevin, me too :P
00:48
<shu>

I don't find this convincing here because -0 is already in the language, and returing it from a new function just adds more places to be careful by a limited number (in the places where you are inlining this built-in).

And now we are explicitly aware about this -0, it could be even be explicitly called out in the spec by saying why we return it so that implementers don't miss it.

you don't find what i said about manual inlines convincing because we can be more vigilant?
00:48
<rbuckton>
For additional reference, C#'s Enumerable.Sum also returns positive zero for an empty list.
00:48
<Michael Ficarra>
parseInt('-0') oh no exploits
00:48
<shu>
i mean can i hear a positive argument for why you want it to be -0
00:48
<snek>
technically you can subtract a list, its just not a thing
00:48
<shu>
i said the exploit thing tongue in cheek
00:49
<Michael Ficarra>
maybe ask Duncan MacGregor for pointers to the examples from other languages he was referring to?
00:49
<nicolo-ribaudo>
i mean can i hear a positive argument for why you want it to be -0
Well, because all the number combinators return their identity when called with 0 args
00:49
<shu>
is that property relied on
00:49
<shu>
like, for the use cases here
00:50
<shu>
if Python returns +0, i know that ecosystem does a lot of numerical stuff and it doesn't bother them, that gives me one signal
00:50
<shu>
Duncan MacGregor said ruby experienced the opposite thing, i'd like to learn more about that
00:50
<snek>
if Python returns +0, i know that ecosystem does a lot of numerical stuff and it doesn't bother them, that gives me one signal
it doesn't return +0, it returns the integer 0. not a float!
00:51
<shu>
its fsum returns an integer?
00:51
<snek>
oh fsum probably does not
00:51
<snek>
is fsum a thing
00:51
<shu>
i'm specifically talking about fsum because that's what kevin was talking about (i thought)
00:51
<shu>
yes
00:51
<nicolo-ribaudo>

I've relied ib it for .min/.max when I get values some values initially and then other later, so I have an "intermediate min".

As Jordan pointed out however, that doesn't work here so my main argument is "all the others do this, we should not diverge"

00:51
<snek>
ah math.fsum
00:51
<shu>

I've relied ib it for .min/.max when I get values some values initially and then other later, so I have an "intermediate min".

As Jordan pointed out however, that doesn't work here so my main argument is "all the others do this, we should not diverge"

but others do not do this, cf python!
00:52
<jschoi>
Well, because all the number combinators return their identity when called with 0 args

Whether +0 is not an identity of Math.sum depends on what equivalence relation you’re applying to that identity:
=== versus Object.is.

In other words, the question here is which equivalence relation we think is most useful (or least risky) for general code that needs to use Math.sum.

00:52
<shu>

Whether +0 is not an identity of Math.sum depends on what equivalence relation you’re applying to that identity:
=== versus Object.is.

In other words, the question here is which equivalence relation we think is most useful (or least risky) for general code that needs to use Math.sum.

that's not my understanding at all, the identity is over + over floats
00:52
<shu>
how do === and Object.is figure into it?
00:53
<rbuckton>
If there should only be one answer, we either need a reference implementation or comprehensive test cases to ensure all implements do arrive at the same answer.
00:53
<shu>
oh i see, you mean x+id === x or Object.is(x+id, x)?
00:53
<nicolo-ribaudo>
how do === and Object.is figure into it?
Well, from JS you can only observe that +0 is not the identity if you use Object.is at some point, since it's not the identity only for the -0 vs +0 case
00:53
<shu>
yeah fair enough
00:53
<jschoi>
how do === and Object.is figure into it?
Sorry, I mean whether -0 and +0 are considered “equivalent” or different is related to whether we consider both -0 and +0 to be identities on the + operation.
00:54
<jschoi>
Basically what Nicolo just said.
00:54
<shu>
is that an argument for one direction over the other?
00:54
<jschoi>
I think it’s reasonable to return +0 and call it an “identity” (loosely, based on ===).
00:54
<shu>
sgtm
00:55
<Duncan MacGregor>
Duncan MacGregor said ruby experienced the opposite thing, i'd like to learn more about that
Not returning -0.0 has the weird effect that summing two arrays (1 empty) can give a different result from summing the concatenated array.
00:56
<Duncan MacGregor>
Ruby's array summing is a bit of a disaster area in my experience, it has a load of gotchas depending on whether the whole array is floats or not, and other fun things.
00:58
<Duncan MacGregor>
On the SQL and null note we couldn't return null because null is not the identity under addition in JS. null + null give 0. :-(
00:58
<ljharb>
NaN + NaN is NaN tho :-p
00:59
<shu>
Not returning -0.0 has the weird effect that summing two arrays (1 empty) can give a different result from summing the concatenated array.
sorry being slow, meaning if you do sum([]) + sum([1]) vs sum([].concat([1]))?
00:59
<Rob Palmer>
New topic: How come we don't have a table of Stage 2.7 proposals? Is it that none have landed into that bucket yet? https://github.com/tc39/proposals
00:59
<jschoi>
The engines nowadays would optimize Math.sum([0, 1, 2]) such that the intermediate array doesn’t get allocated then GCed, right?
01:00
<ljharb>
yes, that's correct. i'll make a table for it once we have one
01:00
<Michael Ficarra>
even if we wrote down the full algorithm, we would still need to write somewhere that it was computing full precision summation because that is not immediately obvious from looking at 100 algorithm steps
01:00
<Bradford Smith>
ljharb: Would you be satisfied with the spec pointing to documentation for an example known-good algorithm?
01:00
<ljharb>
why not put both? (to both the last two comments)
01:01
<snek>
as an implementor i don't think writing out an algorithm would be helpful, it would just be noise
01:01
<nicolo-ribaudo>
shu: Math.sum([-0]) what would you expect it to return?
01:01
<ljharb>
it would be helpful to me ¯\_(ツ)_/¯
01:01
<snek>
i think linking to an example is far better
01:02
<jschoi>
yes, that's correct. i'll make a table for it once we have one
Does a prior “Stage 3 conditional on approval by reviewers” status retroactively count as “Stage 2.7”? Regarding proposal-array-from-async.
01:02
<nicolo-ribaudo>
If this returns +0, I think it's ok to say "we always normalize -0". But if it can return -0, than you already have to be careful about it when implementing
01:02
<shu>
shu: Math.sum([-0]) what would you expect it to return?
i would expect it to return +0 i think?
01:02
<Duncan MacGregor>
sorry being slow, meaning if you do sum([]) + sum([1]) vs sum([].concat([1]))?
So if you have [-0.0].sum + [].sum that would give a different result to ([-0.0] + []).sum.
01:02
<shu>
If this returns +0, I think it's ok to say "we always normalize -0". But if it can return -0, than you already have to be careful about it when implementing
yes, that's a good point to call out
01:02
<Duncan MacGregor>
On ruby those actually give the same answer because ruby starts with 0 and adds the elements...
01:02
<rbuckton>
even if we wrote down the full algorithm, we would still need to write somewhere that it was computing full precision summation because that is not immediately obvious from looking at 100 algorithm steps
Are there corner cases in arbitrary precision arithmetic that would be useful to point out in the specification? We do that in a number of places in the spec.
01:03
<shu>
So if you have [-0.0].sum + [].sum that would give a different result to ([-0.0] + []).sum.
what are the two sums? +0.0 for the former and -0.0 for the latter?
01:03
<nicolo-ribaudo>
Ok so my position is that Math.sum([-0]) and Math.sum([]) must return the same result. I would prefer both to return -0, but as long as they return the same value I'm fine
01:03
<ljharb>
Does a prior “Stage 3 conditional on approval by reviewers” status retroactively count as “Stage 2.7”? Regarding proposal-array-from-async.
i believe we need explicit consensus on 2.7 in plenary for anything to go in the table
01:03
<shu>
Ok so my position is that Math.sum([-0]) and Math.sum([]) must return the same result. I would prefer both to return -0, but as long as they return the same value I'm fine
that's pretty reasonable, i agree with that
01:03
<Duncan MacGregor>
what are the two sums? +0.0 for the former and -0.0 for the latter?
That's what they should be, if ruby didn't have the bug that [-0.0].sum gives +0.0
01:04
<ljharb>
bakkot: mark me reviewed; altho i think the example should be a link and not "i have to google now"
01:04
<shu>
what i'm confused
01:04
<Duncan MacGregor>
I did say Ruby's summation was a mess. :-)
01:07
<bakkot>
Are there corner cases in arbitrary precision arithmetic that would be useful to point out in the specification? We do that in a number of places in the spec.
there's cases with NaN/infinity/-0, which are handled explicitly; no other corner cases except overflow as long as inputs are finite (and it's hard to write down the overflow one)
06:26
<Chris de Almeida>
for the notes, which Justin offered explicit support to advance math.sum ?
06:26
<Chris de Almeida>
I think it was JRL... ?
09:41
<Justin Ridgewell>
Not me
09:41
<Justin Ridgewell>
Too many Justins.
17:57
<Luca Casonato>
Can someone in the room find someone from ServiceNow to pick us up from the reception? There is 10 of us stuck at reception here
18:14
<Chris de Almeida>
please add your name to the attendees list at the top of the meeting notes
18:20
<Michael Ficarra>
I disagree that "the syntax part of it would be the part slowing it down"
18:20
<Michael Ficarra>
the data model is just as likely to be problematic as the syntax
18:21
<nicolo-ribaudo>
Eemeli mentioned that this data model ends up working also with the other known formats though
18:22
<Richard Gibson>
FYI, the data model is at https://github.com/unicode-org/message-format-wg/tree/main/spec/data-model
18:27
<Richard Gibson>
a Message is either a PatternMessage (with declarations and a pattern) or a SelectMessage (with declarations and selectors for indexing into variants, where each Variant is a list of keys to match and a pattern. And Pattern is an array in which each element is either a string or an Expression (representing e.g. a variable) or a Markup (representing something analogous to an HTML/XML start/end tag).
18:34
<Justin Ridgewell>
Can we just version the syntax parser? Sorry, haven’t been able to listen to most of the proposal.
18:37
<Justin Ridgewell>
If this is already going to be a spec at another standards body.
18:37
<Michael Ficarra>
it already is versioned: 2
18:38
<bakkot>
shu: did not hear comments from you on intl.messageFormat; would you be ok with it going for stage 2 with just the data model and not the syntax?
18:40
<shu>
yes, that's fine with me
18:40
<shu>
my concerns need some systemic approach to address, and wouldn't be productive to ask individual proposals to deal with them
18:41
<shu>
to wit, concerns with how we distribute stdlib additions that won't benefit from independent implementations
18:45
<littledan>
I wouldn't want to add all identity escapes to Unicode RegExps; that'd limit our evolution possibilities
18:46
<bakkot>
agreed but I wouldn't want to use any \+punctuator escapes for anything other than identity escapes, that would be very confusing
18:46
<bakkot>
so I don't think this actually meaningfully limits the language evolution
18:47
<littledan>
agreed but I wouldn't want to use any \+punctuator escapes for anything other than identity escapes, that would be very confusing
yes, I agree with that as well
18:50
<Bradford Smith>
ljharb: Didn't you intend to ask for stage 2.7?
18:50
<Bradford Smith>
did I miss that?
18:50
<ljharb>
only if no changes were to be made
18:50
<rbuckton>
agreed but I wouldn't want to use any \+punctuator escapes for anything other than identity escapes, that would be very confusing
In general I agree that would be a bad idea, but I'd still rather not carve out syntax space across the board
18:51
<ljharb>
since nearly everyone wanted the change, i'll ask for it at the next meeting instead
18:51
<Bradford Smith>
right, ok
18:51
<Michael Ficarra>
bakkot: I like Haskell's \& which terminates variable-length escapes that precede it
18:52
<ljharb>
oof, white on light blue is a very hard to read contrast :-/
18:54
<bakkot>
this slide needs a bright red drop shadow on the text
18:54
<nicolo-ribaudo>
This transcriptionist is getting capitalization right even for terms not on the slides (SharedArrayBuffer)
18:54
<bakkot>
for readability :)
18:54
<nicolo-ribaudo>
I love them
18:54
<jschoi>
Time to audit Shu’s slides for WCAG compliance.
18:56
<Michael Ficarra>
yeah this transcriptionist seemed much better than usual
19:00
<Justin Ridgewell>
it already is versioned: 2
But the concern was that it would change. Well, if it changes, give the new DSL a different parser version.
19:00
<Justin Ridgewell>
Ie, split the parser from the format.
19:00
<bakkot>
uhhhh why is the meeting being recorded now
19:00
<snek>
did the presentation just say someone is recording
19:00
<bakkot>
I am fine with Shu being recorded if he wants that but I would prefer not to be recorded
19:00
<nicolo-ribaudo>
This transcriptionist is getting capitalization right even for terms not on the slides (SharedArrayBuffer)
Aaand they just switched to somebody that puts newlines everywhere
19:02
<Michael Ficarra>
noooooooooo
19:09
<Chris de Almeida>
to reiterate: I accidentally triggered a kb shortcut that started the recording in zoom and immediately stopped it. I think it was recording for maybe... 1 second?
19:09
<Chris de Almeida>
why there is no confirmation for that, I have no idea
19:09
<ljharb>
zoom pops up a warning when it starts, but doesn't remove the recording when it stops, so i didn't realize it had stopped
19:10
<Chris de Almeida>
zoom would show it's recording near the top of the window IIRC
19:10
<Chris de Almeida>
in any case, def not recording, and apologies for the scare!
19:11
<rbuckton>
Duncan MacGregor: Based on our conversations in the shared structs proposal, anything that could block would also have an async counterpart that could be used in the main thread (e.g., the "async locking" primitives discussed on one of the slides).
19:14
<rbuckton>
Very much want non-blocking, concurrent collections for this case.
19:15
<Mathieu Hofman>
Luca Casonato: do you have pointers where the move to remove the wasm handshake was discussed? I'd like to follow the developments, in particular regarding to this agent global syscall table it would likely introduce
19:18
<rbuckton>
since danielrosenwasser's question wasn't asked verbally, it may be worthwhile to copy it into the notes for anyone reading afterwards
19:18
<Duncan MacGregor>
Duncan MacGregor: Based on our conversations in the shared structs proposal, anything that could block would also have an async counterpart that could be used in the main thread (e.g., the "async locking" primitives discussed on one of the slides).
Thanks, I think an async API for condition varialbe might work, but my experience of writing concurrency libraries and reviewing concurrent code in general is that we should absolutely aim for higher level constructs because building them correctly from lower level ones is really hard and is not something we should generally be steering developers towards doing.
19:18
<nicolo-ribaudo>
Done
19:19
<snek>
tokio is a good prior art for async concurrency primitives
19:19
<rbuckton>
Thanks, I think an async API for condition varialbe might work, but my experience of writing concurrency libraries and reviewing concurrent code in general is that we should absolutely aim for higher level constructs because building them correctly from lower level ones is really hard and is not something we should generally be steering developers towards doing.
In general, if you are depending on asynchrony to handle concurrency you can't expect performance if you are granular with locks in the main thread. In the browser, you're more likely to see Worker to Worker interactions with fine-grained locks, and more coarse-grained locks from UI thread to Workers.
19:21
<snek>
i think mark would say we should be building erlang instead of c++
19:22
<danielrosenwasser>
since danielrosenwasser's question wasn't asked verbally, it may be worthwhile to copy it into the notes for anyone reading afterwards
apologies, didn't want to exhaust the timebox while I scrambled for the mic
19:22
<nicolo-ribaudo>
apologies, didn't want to exhaust the timebox while I scrambled for the mic
Nah it's perfectly fine to not speak -- everybody sees TCQ anyway and the notes are manually edited for a reason :)
19:24
<shu>
can i get a timebox check?
19:26
<Chris de Almeida>
10m
19:26
<Chris de Almeida>
9 min
19:27
<Chris de Almeida>
8 min
19:27
<Michael Ficarra>
we really need TCQ to display the time remaining
19:28
<nicolo-ribaudo>
6 and three quarters
19:32
<Rob Palmer>
3 mins
19:34
<Rob Palmer>
1 min
19:34
<snek>
55 seconds
19:34
<nicolo-ribaudo>
50
19:34
<bakkot>
what else are we even going to do in the remaining time before lunch though?
19:34
<Luca Casonato>
Luca Casonato: do you have pointers where the move to remove the wasm handshake was discussed? I'd like to follow the developments, in particular regarding to this agent global syscall table it would likely introduce
No. This is just what I understood from our initial call with Conrad.
19:34
<snek>
i am also curious of this kevin
19:38
<rbuckton>
If WASM has shared structs and concurrency primitives, and JS doesn't, it will be almost no time between availability in WASM and the first shared-structs package on NPM that makes it available in JS with a poorer experience than we could provide.
19:38
<iain>
Improving the JS/Wasm API seems like a good thing to do independent of our decision here
19:39
<Michael Ficarra>
what else are we even going to do in the remaining time before lunch though?
chairs asked me to do iterator chunking
19:39
<bakkot>
if we get wasm shared objects I'm immediately going to write a JS library which uses wasm and proxies to implement the shared structs proposal
19:39
<bakkot>
I think the JS proposal can be almost completely polyfilled based on the wasm one
19:39
<snek>
binaryen about to get a lot of npm downloads
19:40
<Rob Palmer>
Is Ben Allen in this room?
19:40
<Ben>
Yes
19:40
<rbuckton>
I think the JS proposal can be almost completely polyfilled based on the wasm one
Except syntax and the handshake complexity, and I'd really prefer we have actual syntax for this in JS.
19:40
<ljharb>
Except syntax and the handshake complexity, and I'd really prefer we have actual syntax for this in JS.
the current proposal has no syntax, does it?
19:40
<rbuckton>
I've used the dev trial for shared structs, and syntax is so much better.
19:41
<rbuckton>
the current proposal has no syntax, does it?
The proposal intends to have syntax by stage 2.
19:41
<rbuckton>
The dev trial does not
19:41
<ljharb>
ah :-/
19:41
<bakkot>
Except syntax and the handshake complexity, and I'd really prefer we have actual syntax for this in JS.
handshake you can do if the library is run in the worker as well. for sure agreed that syntax would be good. this is mostly pointing out that erights' objection just does not make sense because we'll do it in JS anyway
19:41
<ljharb>
syntax, but the things produced are objects, not primitives?
19:41
<rbuckton>
yes, objects
19:41
<bakkot>
syntax, but the things produced are objects, not primitives?
the syntax is mostly just a special kind of class declaration
19:42
<ljharb>
seems strange to have syntax for that then
19:42
<ljharb>
oh ok, for declaration but not usage?
19:42
<shu>
yeah it's for declaring the "types"
19:42
<rbuckton>
We cannot leverage class as is due to how fixed layout is determined, but the syntax is very close to class syntax.
19:42
<snek>
class(shared)
19:44
<rbuckton>
The are a number of additional restrictions on shared structs that aren't compatible with class construction semantics, and one of our areas of exploration was how to handle thread-local prototypes and correlating struct definitions between two threads.
19:47
<rbuckton>
but essentially the syntax is the same as class. The struct keyword essentially indicates the difference in construction and layout. IIRC, syntax is also helpful for VMs that want to do static analysis and leverage the declaration to determine fixed layout.
19:50
<rbuckton>
handshake you can do if the library is run in the worker as well. for sure agreed that syntax would be good. this is mostly pointing out that erights' objection just does not make sense because we'll do it in JS anyway
I'd started experimenting with building this on top of a growable SharedArrayBuffer as well, though in that case you need to roll your own malloc and per-thread ref counting. And its not as fast due to all of the indirection and wrapping.
19:51
<bakkot>
and also serialization, presumably
19:51
<iain>
There's one possible world where this gets implemented in Wasm and then the syntax / polyfill is (at least initially) provided via build-time tooling. In particular, because Wasm functions don't close over nearly as much state as JS functions, shared behaviour seems strictly easier / cleaner to specify and implement in Wasm.
19:51
<rbuckton>
There has been a lot of interest inside of Microsoft around the shared structs proposal.
19:53
<rbuckton>
There's one possible world where this gets implemented in Wasm and then the syntax / polyfill is (at least initially) provided via build-time tooling. In particular, because Wasm functions don't close over nearly as much state as JS functions, shared behaviour seems strictly easier / cleaner to specify and implement in Wasm.
I've been very tempted to build struct syntax in TypeScript using the dev-trial implementation, even if only to test out the syntax. I'm not sure it is something we would ship if we never shipped syntax in JS.
19:55
<shu>
There's one possible world where this gets implemented in Wasm and then the syntax / polyfill is (at least initially) provided via build-time tooling. In particular, because Wasm functions don't close over nearly as much state as JS functions, shared behaviour seems strictly easier / cleaner to specify and implement in Wasm.
i think this is a misunderstanding -- wasm behavior easier within wasm. once it crosses the boundary you have the exact same problem
19:55
<shu>
another way to look at it is, the TLS syscall table is solving the attaching behavior problem
19:56
<ljharb>
bakkot: it's much easier to write your own function for it yes, but it's still not as ergonomic and readable as something built-in would be
19:58
<Duncan MacGregor>
I think in Java, because it go for structural types but only nomitative ones, you woul chunk things in a stream by using a collector to build the objects that represent the chunks.
19:59
<iain>
shu: What do you mean by crossing the boundary? Suppose we improve Wasm-JS interop by (eg) adding a section to wasm that lists the exposed fields/methods, and expose those to JS. My understanding is that in that case, your shared wasm object would have a shared shape that points to shared methods, all of which live in the shared heap, and you don't have to worry about shared->unshared edges in the same way you do with thread-local shapes.
20:00
<iain>
The obvious downside is that the shared methods all have to be written in wasm
20:00
<shu>
iain: how do you call the shared methods?
20:00
<rbuckton>
As a counterpoint to Mark's argument: Worker and SharedArrayBuffer already exist in JS and you can already get into trouble if you try to write multithreaded code and do so poorly, but that trouble often stems by JS not having adequate support for synchronization primitives and shared data, such that everyone needs to roll their own concurrency mechanism, and that's just plain worse.
20:02
<rbuckton>
You can implement Mutex and ConditionVariable on top of SAB using Atomics today (and I have). You can implement a very limited shared structs on top of SAB today as well (and I have). What's missing is object references and GC support.
20:04
<iain>
shu: Hmm. You access the property, you get some sort of wrapper back that has a local->shared edge, and then you invoke it. Are you saying that the wrapper has the same problem?
20:04
<iain>
It seems like we could spec the wrapper as some sort of opaque immutable type where identity is unobservable, and then avoiding repeated allocations of the wrapper is an implementation detail
20:06
<iain>
I guess identity is observable via comparison
20:08
<iain>
Alternatively, couldn't the wrapper be a shared object itself?
20:58
<shu>
shu: Hmm. You access the property, you get some sort of wrapper back that has a local->shared edge, and then you invoke it. Are you saying that the wrapper has the same problem?
yep, exactly
20:58
<shu>
Alternatively, couldn't the wrapper be a shared object itself?
it could be, but if it's a callable object, that basically means some weird, new exotic function
21:00
<iain>
That still seems preferable to the TLS ephemeron scheme
21:01
<shu>
i'm confused, how is this connected to the TLS ephemeron scheme?
21:01
<snek>
is this the same thing i wanted all those months ago
21:01
<littledan>
I liked the idea of avoiding the wrapper using TLS... aren't these wrappers expensive? how would you avoid repeat allocation?
21:01
<shu>
i might be misunderstanding this doesn't seem connected to the TLS thing
21:01
<shu>
the TLS thing is needed for shared wasm to use unshared JS functions (web APIs)
21:01
<shu>
i thought iain was talking about the other direction: JS calling shared wasm function
21:02
<littledan>
oh sorry for changing the subject; just catching up
21:02
<iain>
shu: I was talking about the local shape thing
21:02
<shu>
local shape?
21:02
<shu>
there are too many streams, sorry, might need to take it from the top at a later time
21:02
<iain>
shu: Thread-local prototypes
21:03
<shu>
iain: how do wrappers help there?
21:05
<iain>
My understanding of this slide deck is that we want to be able to attach behaviour to shared structs, but JS functions are necessarily not shared, so we need the TLS weakmap to assign thread-local prototypes. If wasm functions can be shared, then instead of thread-local prototypes, we can have shared prototypes, so we don't need the TLS weakmap or the ephemeron tracing.
21:05
<shu>
ah i see what you're saying
21:06
<littledan>
I like the idea for sharing behavior by having this TLS point to an object which serves as the prototype of an object. This lets you have getters for fields.
21:06
<littledan>
so then you need a way to allocate a Wasm GC object with a particular TLS field as a prototype [and presumably also a non-shared version, without using TLS]
21:06
<shu>
iain: i think that's morally equivalent to a new exotic callable that's sorta-kinda dynamically scoped. this was written off earlier in the design process because nobody i asked wanted new exotic callables
21:07
<shu>
i'm not deathly opposed to it but it's also a can of worms (i think)
21:07
<iain>
Not sure I understand where dynamic scoping comes in
21:08
<iain>
I was also under the impression that (aside from the question of how we expose it to JS) we got it mostly for free from the Wasm proposal, although I admit that I have been paying more attention to the JS side
21:09
<shu>
suppose the wasm function traps and needs to throw an exception. this exception needs to be materialized somehow. currently this is one of the ways in which functions are "deeply unshareable" in that you create Error instances from the realm in which the function was created
21:09
<shu>
this is a question that JS wrappers of shared wasm functions still need to answer
21:09
<shu>
an easy answer is: the realm of the wrapper, the wrapper is unshared
21:09
<shu>
a harder answer is: maybe the caller realm (what i meant by dynamic scope), since it's a special exotic callable
21:10
<shu>
but i take the point this may be a promising avenue to explore again, in light of the wasm angle
21:11
<iain>
Ah, I see. And the wasm proposal doesn't have to deal with this because the Error instance doesn't exist in wasm
21:11
<iain>
It's just trapping and then the world ends?
21:11
<shu>
yep
21:11
<shu>
and it doesn't have a notion of like "this realm's Array constructor" or whatever either
21:12
<shu>
a lot of the "original sin" comes down imo to JS functions being too first class
21:12
<rbuckton>
... I remember using "LiveScript" on the server around the same time it was introduced for the browser and became known as JavaScript ...
21:13
<rbuckton>
in Netscape SuiteSpot Server, IIRC
21:13
<iain>
Are there implementation issues with a special exotic callable, or is the blocker there just the problem of specifying it?
21:13
<shu>
i haven't thought deeply about impl concerns
21:13
<shu>
IIRC it was more about language complexity
21:14
<iain>
From an implementation perspective I think I would prefer the exotic callable, but maybe there's something I'm missing
21:14
<shu>
(like, these special things have a different .apply or something? different .bind?)
21:16
<iain>
Let's go back to the wrapper idea for a second. Regular non-shared JS object, with the Function prototype for .apply and friends. Freeze it so that it's completely immutable.
21:17
<shu>
which realm's Function prototype?
21:18
<iain>
The current realm? Maybe there's a separate instance per-realm.
21:18
<shu>
then isn't that... TLS prototypes
21:19
<iain>
What I'm trying to think through is whether we can just keep it in a weak map that doesn't care about other threads, because if there's no local edge to it and you collect it, then you just create it again from scratch
21:19
<iain>
You won't have pointer identity, but that's unobservable because we've postulated that we could collect it, so there wasn't another copy of the pointer
21:19
<shu>
oh
21:19
<shu>
that's a different semantics that Luke Wagner brought up in a different context
21:20
<shu>
i didn't have time to get to it during the agenda item
21:20
<littledan>
it's just kinda slow to have all these weak maps and wrappers, isn't it?
21:20
<shu>
yeah
21:20
<shu>
definitely needs to be validated
21:21
<danielrosenwasser>
leobalter: can you add your name to the notes document?
21:21
<snek>
i feel like there is too much nuance for us to ever come up with a more concrete process than what we currently have
21:22
<iain>
shu: SM is working on an architectural review of shared structs. Hoping to have it ready soon, although there's been enough new information today that it will take a little bit to digest it.
21:22
<iain>
Are there regular meetings for this proposal? Maybe I should be attending them
21:23
<shu>
shu: SM is working on an architectural review of shared structs. Hoping to have it ready soon, although there's been enough new information today that it will take a little bit to digest it.
there is a working call on the TC39 calendar, yeah
21:23
<shu>
and cool! looking forward to review
21:24
<Michael Ficarra>
that was a beautiful point Richard Gibson: "lone" objectors are possibly only alone because the people they represent aren't in the room
21:25
<ljharb>
or, are in the room but unwilling to speak up - not everyone has the same comfort level with dissent
21:26
<Michael Ficarra>
I'm not as sympathetic to that ljharb
21:26
<danielrosenwasser>
Shane (SFC) can you add your name to the notes document?
21:26
<snek>
dissenting typically implies responsibility for finding a solution as well, its not something you always want to deal with
21:26
<ljharb>
I'm not as sympathetic to that ljharb
i think sympathy to that should match 1:1 with sympathy to concerns about inhibiting newcomers
21:26
<bakkot>
while that's sometimes true, it's also often not true; some delegates work on things that no one else is really doing, or have concerns about language specification purity which are relevant only to consumers of the language specification, rather than to developers
21:27
<ljharb>
sometimes yes. but there isn't always a solution to be had, and people often have trouble accepting it when there is none.
21:27
<Chris de Almeida>
diffusion of responsibility is often at play
21:30
<Kris Kowal>
At the time that unanimity was established was when only VM implementers were present at the table and there was no point in making a standard that any one of them was unwilling to implement.
21:31
<Kris Kowal>
I’m in favor of keeping the consensus by unanimity, even though we’re not living in that historical context.
21:31
<snek>
i very strongly agree with everything mark is saying right now
21:31
<danielrosenwasser>
Is there a list of "known phrases" that the transcription bot knows about?
21:31
<bakkot>
danielrosenwasser: we have a human transcriptionist
21:31
<bakkot>
oh but for the transcribe bot? yes but it's very very short
21:32
<danielrosenwasser>
EMCAScript keeps getting put in the notes
21:32
<bakkot>
const REPLACEMENTS = [
  [/\bsho(?:e|ot?)\b/gi, 'Shu'],
  [/\b(, )?u(h|m),?\b/gi, ''],
  [/\bIntel\b/gi, 'Intl'],
  [/\bagalya\b/gi, 'Igalia'],
  [/\bregalia\b/gi, 'Igalia'],
  [/\bgalia\b/gi, 'Igalia'],
];
21:32
<leobalter>
I truly wonder if a decision regarding the consensus process requires TC consensus or actual member vote.
21:33
<Chris de Almeida>
the catch 22 which must not be named
21:33
<ljharb>
a member vote would suffice but that'd be a failure of the consensus process that we all currently agree to follow
21:34
<leobalter>
Consensus should be ideal, but it seems like a can of worms otherwise. We are using consensus to change what consensus means. It's not a simple process.
21:35
<bakkot>
i very strongly agree with everything mark is saying right now
I disagree with the idea that "do nothing" is "fail safe". I particularly disagree with it in light of the previous conversation; I really wish it were better understood that failing to provide a good story for parallelism on the web means the experience of using the web is notably slower than it should be, and that is a cost which is measured in small fractions of billions people's lives every day
21:35
<bakkot>
I realize that is maybe dramatic but it's also true and we ought to care about that cost
21:35
<ljharb>
ps if it takes 2 member companies to veto, then that means it only costs $7000 to block anything.
21:35
<leobalter>
Too much that can be discussed as formality. We need this to evolve more to discuss the format
21:36
<ljharb>
I realize that is maybe dramatic but it's also true and we ought to care about that cost
if persuasion and discussion are not effective at convincing objectors to care about that cost then i don't think the solution is silencing that objector's voice
21:36
<shu>
ecma is literally pay to participate though
21:36
<Michael Ficarra>
ljharb: that would be bad faith
21:36
<Michael Ficarra>
we would just ignore it
21:36
<ljharb>
ljharb: that would be bad faith
absolutely it would. but it wouldn't be provable.
21:37
<ljharb>
i'm not saying it's a reasonable tactic, i'm just reinforcing that it's impossible to prevent weaponization
21:37
<snek>
I disagree with the idea that "do nothing" is "fail safe". I particularly disagree with it in light of the previous conversation; I really wish it were better understood that failing to provide a good story for parallelism on the web means the experience of using the web is notably slower than it should be, and that is a cost which is measured in small fractions of billions people's lives every day
i agree that this is frustrating but i can't think of a process that strictly improves this problem in the general sense
21:37
<bakkot>
if the objector will not change their mind, then we weigh the cost of overruling them against the cost of doing nothing, and I think in some cases - notably in the case of parallelism - the cost of doing nothing is overwhelmingly higher
21:37
<littledan>
ps if it takes 2 member companies to veto, then that means it only costs $7000 to block anything.
you can't just pay to block things. Hax tried this and it didn't work.
21:37
<ljharb>
right. so it didn't work despite our current process. so changing our process won't stop it more from working.
21:38
<shu>
it didn't work for one main reason, which is that he was part of the outgroup
21:38
<shu>
the weaponization msaboff alludes to is by members of the long-standing ingroup
21:40
<eemeli>
As we'll likely run out of time here, my thought: We should mitigate the negatives of a lone objector blocking progress. One way to do that would be to automate the re-presentation of decisions with a lone objector at a near-future meeting, allowing and expecting discussion to happen in the interim. So effectively require sustained objection to block a thing with a small minority.
21:40
<Michael Ficarra>
😞 this was nowhere near enough time for this topic
21:41
<bakkot>
As we'll likely run out of time here, my thought: We should mitigate the negatives of a lone objector blocking progress. One way to do that would be to automate the re-presentation of decisions with a lone objector at a near-future meeting, allowing and expecting discussion to happen in the interim. So effectively require sustained objection to block a thing with a small minority.
I think that would actually be worse than the current process; I don't think anyone who lone-objects at one meeting under the current process would not also want to lone-object at the next meeting, so it would just be about whether they had the resources to attend the next meeting
21:42
<bakkot>
which is very much not the criteria we ought to use
21:42
<Michael Ficarra>
omg I agree so hard with Dan right now
21:42
<shu>
you also agreed hard with mark earlier
21:42
<shu>
confused
21:42
<Michael Ficarra>
not me
21:42
<shu>
ah, my bad
21:42
<snek>
i agreed with mark
21:43
<shu>
but yes i also agree with dan
21:44
<littledan>
I should've also said: blocks are really really really discouraging and do stop progress, even if people don't mean it to
21:44
<snek>
i'm not against improving things, i just feel like we're playing with a very delicately balanced bomb
21:44
<leobalter>
I honestly just hope we end some paths for delegate burnout. This is a very sensitive topic and I'd love to keep the convo when time allows.
21:44
<littledan>
Blocks definitely cause delegate burnout, this is unquestionable
21:45
<shu>
it has many knock on effects, delegate burnout the worst among them for individual well-being
21:45
<littledan>
I also should've said: I'm really confident that everyone here just wants what's best for JS, and we're just trying to figure out the way to collect the data and judgements we're all bringing
21:45
<leobalter>
TC39 lost some considerate participations and I totally sympathize with the idea of trying to resolve this. I don't have an answer ready on how we do this.
21:45
<shu>
it encourages to shop venues, and in the limit, it encourages erosion of the weight of tc39 itself
21:50
<Michael Ficarra>
lol stop putting new things on the queue please, we're trying to drain it
21:51
<littledan>
it would be an improvement if voices had the same weight. Right now, we weigh people higher if they have a propensity to veto
21:52
<shu>
i don't think voices should have the same weight
21:52
<shu>
but giving propensity to veto higher weight is much worse than equal weight
21:53
<littledan>
We should understand what different stakeholders represent, and make decisions with that in mind. But I think the committee currently has equality as a goal/mostly shared value, and I hope it stays that way, and that we can reinforce it more.
21:55
<bakkot>

I think I would put it this way:

The veto process means that we say the risk of doing the wrong thing is always more than the risk of doing nothing. And that's just not true. Some things, sugar especially, doing nothing is relatively costless; some things, like new capabilities and APIs for performance, the cost of doing nothing is actually quite high.

Our process should allow seriously weighing the costs of doing nothing, and not privilege the costs of doing the wrong thing as the ultimate determinant.

21:56
<leobalter>
msaboff: I highly encourage we continue discussing this. Thank you for bringing it up to TC39!
21:58
<ljharb>
does anyone remember which meeting shadowrealms was dropped to stage 2?
21:58
<rbuckton>
Per what danielrosenwasser said, it would definitely help if lone dissenters became actively involved in the proposal to help address concerns. Vetoing a proposal and walking away when that proposal has otherwise broad support isn't helpful.
21:58
<shu>
does anyone remember which meeting shadowrealms was dropped to stage 2?
sept 2023 iirc
21:58
<bakkot>
("relatively costless" is the wrong way of putting it, since in every case blocking certainly has costs on delegates, which are quite real and I don't want to leave those out. but the costs are of a different kind than the costs of the web being slower or otherwise worse for users)
21:59
<danielrosenwasser>
To be clear, I am somewhat okay with people saying "this is just a matter of taste", but I am frustrated when the feedback is left as an exercise to the champion.
21:59
<shu>
i am not okay with people saying it's a matter of taste when it's not a matter of taste though!
21:59
<bakkot>
chairs: queue needs advancing
21:59
<snek>

I think I would put it this way:

The veto process means that we say the risk of doing the wrong thing is always more than the risk of doing nothing. And that's just not true. Some things, sugar especially, doing nothing is relatively costless; some things, like new capabilities and APIs for performance, the cost of doing nothing is actually quite high.

Our process should allow seriously weighing the costs of doing nothing, and not privilege the costs of doing the wrong thing as the ultimate determinant.

i agree with this but its also a subjective judgement
21:59
<snek>
how do you come to agreement on it
22:00
<Kris Kowal>
bakkot: That would seem to suggest that we would need different rules for consensus for different kinds of changes. Perhaps we can use consensus to weaken consensus selectively.
22:00
<snek>
but a person "abusing the process" could just... not agree to weaken it
22:01
<littledan>
bakkot: That would seem to suggest that we would need different rules for consensus for different kinds of changes. Perhaps we can use consensus to weaken consensus selectively.
well, in some way we've already been cautiously starting to do this, with non-binding polls for choices that we all agree are aesthetic/unimportant. I think this is really positive and should continue!
22:03
<ljharb>
i agree - ad hoc consensus to allow a lower bar to agreement is a wonderful way to preserve the safety of complete consensus while reducing friction where it's not necessary
22:04
<ljharb>
if we can come up with a way to do that in general, as opposed to ad hoc, that would be great (for scenarios where it applies)
22:04
<nicolo-ribaudo>
I think we need to solve this in abstract, since once somebody wants to block something concrete there is no reason for them to give consensus to ignore their non-consensus
22:04
<ljharb>
i agree with snek tho that it'll be difficult to come up with an objective rubric for that
22:05
<littledan>
These sorts of consensual processes can definitely help us, but we still need some way of handling situations of contentious vetoes.
22:05
<ljharb>
I think we need to solve this in abstract, since once somebody wants to block something concrete there is no reason for them to give consensus to ignore their non-consensus
i agree that solving it in general prevents that kind of potential conflict on an ad-hoc basis
22:05
<leobalter>
does anyone remember which meeting shadowrealms was dropped to stage 2?
September 23
22:05
<Chris de Almeida>
well, in some way we've already been cautiously starting to do this, with non-binding polls for choices that we all agree are aesthetic/unimportant. I think this is really positive and should continue!
yes.. voting on advancing a proposal is a very different kettle of fish compared to voting for bikeshedding-type decisions
22:06
<Chris de Almeida>

I think I would put it this way:

The veto process means that we say the risk of doing the wrong thing is always more than the risk of doing nothing. And that's just not true. Some things, sugar especially, doing nothing is relatively costless; some things, like new capabilities and APIs for performance, the cost of doing nothing is actually quite high.

Our process should allow seriously weighing the costs of doing nothing, and not privilege the costs of doing the wrong thing as the ultimate determinant.

this is a really important point
22:07
<littledan>
yes.. voting on advancing a proposal is a very different kettle of fish compared to voting for bikeshedding-type decisions
one issue is, there isn't always a shared understanding about what's bikeshedding and what's very significant. I often find myself thinking that something is bikeshedding that others thing is very significant.
22:07
<Chris de Almeida>
it is probably a very small number of times it would come up but if there are decisions that need to be made in a timely manner, that could mean the need to vote. this is what the CSS WG does.. but again, ONLY if a decision must be made
22:07
<Chris de Almeida>
one issue is, there isn't always a shared understanding about what's bikeshedding and what's very significant. I often find myself thinking that something is bikeshedding that others thing is very significant.
sure, err on the side of caution in those cases then
22:07
<Michael Ficarra>
TIL
22:07
<ljharb>
i think that's exactly the problem - if we all agree it's bikeshedding the contention doesn't manifest
22:08
<Michael Ficarra>
makes you wonder where these phrases come from
22:08
<Chris de Almeida>

However, if a decision is necessary for timely progress and consensus is not achieved after careful consideration of the range of views presented, the Chairs may call for a group vote and record a decision along with any objections.

22:08
<ljharb>
but when one person thinks something is critical and another thinks it's trivial, it often gets tense
22:08
<Chris de Almeida>

However, if a decision is necessary for timely progress and consensus is not achieved after careful consideration of the range of views presented, the Chairs may call for a group vote and record a decision along with any objections.

from CSS WG charter
22:09
<littledan>
maybe! I find that a lot of these cases are the ones where we make decisions by being held hostage, which can be suboptimal.
22:10
<snek>
what is timely progress
22:10
<Michael Ficarra>
chair discretion
22:11
<Michael Ficarra>
the chair is a very powerful role and I think we kind of take that for granted in this group
22:11
<Michael Ficarra>
they don't need to be this generous
22:11
<ljharb>
historically the chair has had zero power
22:11
<shu>
i think historically the TC39 chair is one of the weaker positions as far as standards body chairs go
22:11
<ljharb>
that power has been slowly increasing, in a good way
22:11
<snek>
our chairs are also delegates, we can't escalate decisions to them without conflict of interest
22:12
<Michael Ficarra>
our chairs reliably recuse themselves when there is a conflict
22:12
<ljharb>
historically also, the chair had no interest in the specifics of language changes.
22:13
<Michael Ficarra>
don't ever elect me as chair because I wouldn't hesitate to wield its power (thoughtfully)
22:13
<Rob Palmer>
Thank you for noticing Michael. Each meeting the chairs maintain a list of topics in advance that we have an interest in to ensure that we do not chair those topics. But we don't really shout about this.
22:14
<Chris de Almeida>
I can tell you unequivocally that the chairs, as chairs, feel strongly about making absolutely no decisions for the committee, as much as possible, beyond purely administrative things and similar things where burdensome to committee
22:14
<Michael Ficarra>
I would also be fine with the chairs being a little more authoritative, especially during plenary
22:15
<ryzokuken>
honestly, if we did strongly decide to do something like this, I'd recommend this be done by the secretaries
22:15
<Chris de Almeida>
the less noticeable we are, the better
22:16
<littledan>
honestly, if we did strongly decide to do something like this, I'd recommend this be done by the secretaries
do you mean by Samina, the TC39 secretary?
22:16
<ryzokuken>
do you mean by Samina, the TC39 secretary?
yes
22:16
<ljharb>
if we're worried about a conflict of interest, ecma receives more money from ordinary members than associates, so there may be a potential conflict there (obv,. hopefully not)
22:16
<ryzokuken>
as pointed out above, chairing the meeting is an administrative role that allows us to facilitate topics we are neutral about while being delegates
22:16
<littledan>
as pointed out above, chairing the meeting is an administrative role that allows us to facilitate topics we are neutral about while being delegates
yeah it just sounds like too much work to do this and also mediate all conflicts...
22:17
<Michael Ficarra>
the less noticeable we are, the better
we used to have a chair that you could forget was even in the room (aside from the snoring), and I can assure you, I prefer the chairs to be more noticeable than that
22:18
<Chris de Almeida>
I mean, there's nuance, but I think you get what I mean 🙂
22:18
<ljharb>
doesn't mean we want to overcorrect tho :-)
22:19
<ryzokuken>
yeah it just sounds like too much work to do this and also mediate all conflicts...
suddenly the role has a lot more responsibility and weight and I don't think any organization would be incentivized to allow delegates to be in this position
22:19
<nicolo-ribaudo>
I like the charis giving chocolate and hats to bribe delegates
22:19
<Chris de Almeida>
to put it simply, we don't want to be making decisions that are committee decisions
22:21
<littledan>
right so I think we need a procedure for delegates to contest vetoes (after the meeting, since during the same meeting would be too fast/chaotic/unconsidered)
22:21
<littledan>
rather than asking the chairs to constantly adjudicate by themselves on everything
22:23
<ljharb>
and we now have a Stage 2.7 section https://github.com/tc39/proposals?tab=readme-ov-file#stage-27
22:24
<shu>
anyway more dispassionately i also think the lone veto thing actually is great for small groups (the older, smaller, closer-knit TC39) but doesn't scale
22:25
<shu>
like you don't want a family of 4 to vote on all decisions, that will be bad
22:26
<Kris Kowal>
Spec invariants and subgroups would go a long way to making TC39 scale. I am eager to write a blank check to Intl.
22:27
<bakkot>
I am somewhat less eager to write a blank check to Intl
22:27
<Kris Kowal>
Yeah, I don’t mean everyone. I mean me.
22:27
<bakkot>
I am fine leaving the decisions which are just internationalization to subgroups, but not overall questions of API design
22:27
<snek>
bakkot you'll need to sustain your objection to writing a blank check to intl
22:28
<Kris Kowal>
A “I hereby waive my interest in a veto on Intl provided it maintains these here invariants.”
22:28
<rbuckton>
I am fine leaving the decisions which are just internationalization to subgroups, but not overall questions of API design
Not even if its a subgroup focused on general API design within JS?
22:28
<bakkot>
rbuckton: sorry, I was referring only to Intl specifically
22:29
<bakkot>
I am fine with subgroups in general but not taking the output of any subgroup wholesale into the language
22:29
<bakkot>
there are some questions best left to subgroups but most proposals involve some questions which are not of that kind
22:30
<Kris Kowal>
The DOM as an API subgroup.
22:30
<shu>
my brother i'm pretty sure we are the subgroup
22:31
<ljharb>
i definitely think that establishing a thorough list of invariants will drastically reduce lone objections
22:32
<Richard Gibson>
seems pretty obvious to me
22:33
<bakkot>
thinking about the lone objections I can remember I am not sure I can think of any which could have been handled by a list of invariants? except invariants like "no new unreachable intrinsics" or "no shared-state parallelism", neither of which would have gotten consensus to be on such a list
22:34
<ptomato>
I would like to see a thorough list of invariants be a high-priority goal regardless, but I agree with Kevin here
22:35
<littledan>
the invariants project will need to contend with the fact that a lot of the invariants that people care about the most will be absent from the list of invariants which has committee consensus. For this reason, I think the first step should be to document all the concerns that some people are thinking about (as has already begun in how-we-work), rather than get consensus on it.
22:36
<shu>
i don't like the idea of consensus seeking on invariants
22:36
<shu>
invariants i think are particular reflections of goals
22:36
<shu>
i want some semblance of understanding of goals
22:36
<ljharb>
(re kevin and dan) that's a fair point. having a list of invariants, some of which have consensus and many of which won't, would still be helpful
22:37
<shu>
goals as scoped as possible, of course
22:37
<ljharb>
(re shu) also a good point
22:37
<shu>
i don't think "more better js" is a valid goal
22:43
<leobalter>
shu: would you mind taking a quick look at the conclusion/resolution for ShadowRealm? I want to make sure I'm not missing anything.e
22:45
<rbuckton>
I kind of like the idea of markdown fences as an alternative to escaping ` and ${ and end-of-string \, but I don't have a strong preference.
22:46
<ljharb>
it might be nice to allow N backticks, paired, to change what needs to be escaped?
22:47
<bakkot>
foo````

is already legal, alas

22:47
<ljharb>
like with a single backtick, you have to escape backticks; but if you put, say, three, you'd only have to escape a set of triple backticks
22:47
<rbuckton>
I thought that was in the proposal when I reviewed it last week.
22:47
<ljharb>
ah true
22:47
<shu>
shu: would you mind taking a quick look at the conclusion/resolution for ShadowRealm? I want to make sure I'm not missing anything.e
done, lgtm
22:47
<bakkot>
foo````

is already legal, alas

legal and at least possibly sensible e.g. https://gist.github.com/michaelficarra/70ce798feb25fdc91508f387190053a1
22:47
<bakkot>
that said, it might still be web-compat
22:48
<bakkot>
but changing existing parses is scary
22:48
<rbuckton>
When I looked at it before, it was @```, with a n+3 backticks that must be matched, as long as its one more backtick than the number of contiguous backticks in the body.
22:49
<jschoi>
foo````

is already legal, alas

…Wait, what does this parse as, again?
22:49
<Justin Ridgewell>
Syntax isn't a Stage 1 concern…
22:49
<Justin Ridgewell>
Do we want to explore this? If so, we'll define syntax when we explore it.
22:50
<rbuckton>
but markdown fences are tricky in that `` ` `` ignores the leading and trailing whitespace to avoid it being treated as a contiguous run of backticks
22:50
<bakkot>
…Wait, what does this parse as, again?
(foo``)``
22:50
<Richard Gibson>
…Wait, what does this parse as, again?
foo````

is the same as

(foo``)``
22:51
<snek>
should've added an early error on that
22:51
<snek>
or a lookahead
22:51
<bakkot>
yeah I tend to agree
22:51
<bakkot>
oh well
22:52
<Michael Ficarra>
where's the fun in that snek ?
22:52
<snek>
lol
22:52
<bakkot>
doubled punctuators being special is well-precedented
22:52
<Michael Ficarra>
it's JavaScript, you're supposed to be able to construct horrors
22:52
<snek>
lets use r#""# like rust
22:53
<bakkot>
it's JavaScript, you're supposed to be able to construct horrors
foo`` ``

is not... less horrible

22:53
<danielrosenwasser>
Meta: do people find it valuable to get constraints for later stages, even at earlier proposal advancement meetings? I would think it is helpful.
22:53
<bakkot>
lets use r#""# like rust
or just r"" "", I don't think you need the #s?
22:54
<leobalter>
I really like the problem we are trying to resolve having used this feature within different languages ie Perl. Even thou, I don't know if I'd have the energy to pursue this string proposal considering it needs us to elect a token
22:54
<Justin Ridgewell>
Sure, I think "desire for minimal syntax" is a good thing to bring up, but "I don't like `#" isn't
22:55
<rkirsling>
yeah Mark's reaction was basically my reaction too
22:55
<bakkot>
I want a better String.raw and would consider that in scope for this proposal...
22:55
<bakkot>
https://github.com/tc39/proposal-string-cooked/issues/13
22:56
<ptomato>
Meta: do people find it valuable to get constraints for later stages, even at earlier proposal advancement meetings? I would think it is helpful.
for me personally, yes; although in the form of 'potential concerns', rather than 'constraints'; I believe it's premature to have dealbreakers for future stages at that point
22:57
<rbuckton>
I want a better String.raw and would consider that in scope for this proposal...
Isn't the point of this that you don't need String.raw with it? Why would that be in scope?
22:57
<nicolo-ribaudo>
Meta: do people find it valuable to get constraints for later stages, even at earlier proposal advancement meetings? I would think it is helpful.
I would prefer to not always ask for consensus at the end of the timebox, but have some time after getting stage 1 for "ok now, anything else I should consider?"
22:58
<bakkot>
Isn't the point of this that you don't need String.raw with it? Why would that be in scope?
part of the problem statement, which is the stage 1 thing, is that String.raw doesn't work
22:58
<Bradford Smith>
Maybe "here documents for JS"
22:58
<bakkot>
hence if we could have a version of String.raw which had fewer sharp edges, that would be in the direction of solving the problem
22:58
<rbuckton>
Isn't that just a side-effect of special \ escapes?
22:58
<ljharb>
what's the exact title?
22:59
<littledan>
bakkot: Did you agree with my problem statement? Please feel free to edit it
22:59
<littledan>
what's the exact title?
"Improved escapes for template literals" I think?
22:59
<rbuckton>
A better String.raw doesn't solve \`, \${, and end-of-string \
22:59
<bakkot>
bakkot: Did you agree with my problem statement? Please feel free to edit it
sgtm
23:00
<rbuckton>
That is 100% a syntax issue, no amount of API support can fix it.
23:01
<rbuckton>
Maybe there are improvements that could be made for String.raw, but that won't address the main concerns this proposal seeks to address.
23:02
<hax (HE Shi-Jun)>
https://github.com/tc39/proposal-string-cooked/issues/13
String.rare does not really solve the problem, u still need to do many escaping, and it also make the escaping rule much complex.
23:04
<Chris de Almeida>
NB: topics have shuffled a bit on the schedule
23:06
<hax (HE Shi-Jun)>
When I looked at it before, it was @```, with a n+3 backticks that must be matched, as long as its one more backtick than the number of contiguous backticks in the body.
This is the draft in repo, I use Swift-style in the slides because I thought the concrete syntax is not important in stage 1 meeting. Sorry for bring confusion.
23:06
<rbuckton>
As a syntax, you don't need to limit yourself to @ and # as there are other infix tokens that could be made into a prefix token. For example, you could use \``` ... ``` to mean "I've done all the escaping I need to do at the start and end of the string"
23:07
<hax (HE Shi-Jun)>
Yeah, I understand there are many possibilities, I just use the syntax which already have precedents in other languages as example.
23:07
<rbuckton>
Infix tokens do cause problems for tagged templates, though \``` doesn't
23:08
<hax (HE Shi-Jun)>
Maybe "here documents for JS"
But if "improved template literal" it very unlikely we could have "here doc" style solution.
23:16
<Justin Ridgewell>
Maybe there are improvements that could be made for String.raw, but that won't address the main concerns this proposal seeks to address.
I think you just need to partially cook the raw string
23:17
<Justin Ridgewell>
The same way dedent is (fully) cooking the dedented raw string
23:17
<Justin Ridgewell>
You'll still need to escape the 3 cases, but those escape sequences won't appear in the rare output (all other escapes would)
23:20
<Bradford Smith>
But if "improved template literal" it very unlikely we could have "here doc" style solution.
const myEmbeddedString = String.dedent(
``delimiter text``
    Whatever I want
    to have here
    as long as this ends with
``delimiter text``);
23:20
<rbuckton>
I think the interesting thing about the proposal is that you don't need to escape anything, with the exception being ${, but that could also be tied to the opening of the fenced string literal. The Explainer used n+1 @ tokens, but could just as easily use n+1 \ tokens, etc.
23:23
<hax (HE Shi-Jun)>
const myEmbeddedString = String.dedent(
``delimiter text``
    Whatever I want
    to have here
    as long as this ends with
``delimiter text``);
Not sure how it look like template string (except it use backticks :P ), a problem of here doc style is normally it only support defining end delimiter but we also need to deal with interpolation delimiter.
23:23
<nicolo-ribaudo>
Maybe there are improvements that could be made for String.raw, but that won't address the main concerns this proposal seeks to address.
A string tag that is like String.raw but it replaces \<backtick> with <backtick> and removes backslashes at the end of template parts
23:24
<rbuckton>
That still requires escaping in the literal
23:25
<Bradford Smith>
Not sure how it look like template string (except it use backticks :P ), a problem of here doc style is normally it only support defining end delimiter but we also need to deal with interpolation delimiter.
Better: normal template literal but new substitution syntax.
const myEmbeddedString = String.dedent(Normal template content ${<<hereDocEndText>> Whatever I want to have here as long as this ends with <<hereDocEndText>>});
23:25
<hax (HE Shi-Jun)>
yeah, my goal is to avoid escaping. which means, whatever text you have, u could just paste it to js source code , wrap it in a raw literal, without modifcations.
23:26
<Justin Ridgewell>
I think the interesting thing about the proposal is that you don't need to escape anything, with the exception being ${, but that could also be tied to the opening of the fenced string literal. The Explainer used n+1 @ tokens, but could just as easily use n+1 \ tokens, etc.
It still doesn't address \ at the end of the template, so some escaping will be needed regardless. There was a thread in Google's internal TypeScript chat group about why this case wasn't working with String.raw
23:28
<hax (HE Shi-Jun)>
It still doesn't address \ at the end of the template, so some escaping will be needed regardless. There was a thread in Google's internal TypeScript chat group about why this case wasn't working with String.raw
it could. \ should have no effect on parsing raw literal.
23:28
<rbuckton>
If a raw literal syntax does no escaping, then a trailing \ is just a \. the only thing it looks for is a balanced set of ` characters
23:29
<hax (HE Shi-Jun)>
Yeah, we just need some mechanism to define the ending token and the interpolation token.
23:29
<rbuckton>
\```\```

would be the string \. The only caveat, being a string consisting only of `

23:30
<rbuckton>
element or matrix did not like that...
23:30
<Justin Ridgewell>
Even \x20 isn't transformed? I need to pay better attention.
23:30
<hax (HE Shi-Jun)>
This is why I use swift-style in the slide, because swift style only use number of # to define both token, which IMO the simplest solution. But I don't know how others think about "simple"...
23:31
<hax (HE Shi-Jun)>
Even \x20 isn't transformed? I need to pay better attention.
if Swift style, it allow u to reenable escaping by \#x20
23:31
<nicolo-ribaudo>
This is why I use swift-style in the slide, because swift style only use number of # to define both token, which IMO the simplest solution. But I don't know how others think about "simple"...
If there are concerns about "wasting" #, you could consider using @ since I don't think anybody would ever want to use it for anything other than decorators anyway
23:32
<rbuckton>
Even \x20 isn't transformed? I need to pay better attention.
I think that's correct, from my interpretation of the proposal repo
23:32
<Justin Ridgewell>
if Swift style, it allow u to reenable escaping by \#x20
How do you represent that inside a string, then?
23:32
<hax (HE Shi-Jun)>
How do you represent that inside a string, then?
Increase the number of #
23:32
<Justin Ridgewell>
More #?
23:33
<Justin Ridgewell>
Yah
23:33
<Justin Ridgewell>
Ok
23:34
<hax (HE Shi-Jun)>
On the other side, C# raw strings use two symbols: the number of " for end token, the number of $ for interpolation token.
23:34
<hax (HE Shi-Jun)>
The draft in the repo use C# style.
23:34
<hax (HE Shi-Jun)>
Personally I feel Swift style is much "simple" :P
23:42
<hax (HE Shi-Jun)>
One point is, if only use repeated `(or any repeated single char) as end token, it significantly has more conflict probability than combinations like `#.
23:52
<Rob Palmer>
The removal of the curly brackets dramatically helps me absorb the syntax here.
23:53
<nicolo-ribaudo>
As a syntax, you don't need to limit yourself to @ and # as there are other infix tokens that could be made into a prefix token. For example, you could use \``` ... ``` to mean "I've done all the escaping I need to do at the start and end of the string"
With this syntax, how would you write a string that starts with a backtick?
23:53
<nicolo-ribaudo>
^ Is this problem solvable in any way?
23:54
<bakkot>
nicolo-ribaudo: require that triple-backtick strings have a leading and trailing newline, and strip those from the output