00:02
<justingrant>
Sorry all for being late to reply to Temporal-related posts above. Was so relieved to be done with my 15 mins of fame this morning that I forgot to check the delegates channel afterwards. πŸ˜„ I'll add a few notes and replies now.
00:06
<justingrant>
bterlson: is the remaining point for Temporal already on the list of overflow topics for tomorrow or should I request that somewhere in particular?
I didn't see a response to this so I went ahead and added Temporal to the overflow section in the HackMD page. If this was wrong, please feel free to revert and let us know about the correct process. Thanks!
00:11
<justingrant>
and nobody disputes that temporal's problem space is a hellish nightmare
Finally, we've found an invariant we can all agree with! πŸ˜„
00:20
<justingrant>
it can be very hard to figure out what one did wrong with APIs like this, at any experience level. good error messages help but aren't always sufficient.

Speaking of error messages, one suggestion I'd have for the committee: a standardized way for the spec to provide hints to implementers about error messages, and guidelines for proposal authors for when to provide those hints in the spec. Proposal authors (especially if the proposal's polyfill gets a lot of use) have a lot of tribal knowledge about the requirements for error messages, but AFAIK there's not really an "official" way to convey that knowledge to implementers. Nor is there a requirement that proposal authors think through the "how are users likely to misuse this API and what should the error message say to help them?" problem. I don't think that implementers should be required to use any particular error message, but IMO having more clarity and consistency in error messages across implementations seems like a good idea, both to help users and to avoid inevitable churn from bug reports asking to improve error messages after the implementation ships. Also, implementers may not have insight into the kinds of bugs that users will run into, so they may not be in the best position to write the most helpful error message text without getting those bug reports.

I'm not proposing any specific solution, but did want to highlight the problem and see if there was any existing prior art on the committee around this issue.

00:36
<justingrant>
I'm not saying that the options bag should be optional. But if you pass an options bag without a smallestUnit, then round should be the identity.

We'll plan to spend our overflow time tomorrow focusing on this question. Reading the replies above, I believe that there are three possible solutions:

  1. .round({}) is allowed (and does nothing), but .round() throws.
  2. Both are accepted and do nothing.
  3. Both throw.

The current Temporal Stage 3 proposal uses (3). There were two reasons the champions selected (3): first, because it's a no-op and likely a programmer bug, and second for defense against typos in the property name like .round({smalestUnit: 'second'}) which would be treated the same as .round({}). (Sadly there's no typo defense for optional property names without breaking extensibility, but our opinion was that preventing at least some bugs was better than preventing no bugs.)

One request I'll relay from ptomato: this proposal is already in Stage 3, so we'd ask for there to be a really persuasive case to change the existing plan of record. The default should be that we stick with what's already been approved, because we really want to get this API shipped soon!

00:47
<justingrant>

shu : is ftang in the loop for all these normative changes and bug fixes?
ptomato: yes, he found most of them, but I am pretty sure he read the slides as well. I'll double check at the next Temporal meeting

We also implemented the following process:

  • PRs that affect the spec text are marked with a spec-text label in GH https://github.com/tc39/proposal-temporal/pulls?q=is%3Apr+label%3Aspec-text
  • PRs that don't affect the spec (e.g. changes to docs, polyfill, tests, build tools hell, etc.) are marked no-spec-text
  • PR authors who forget to put the right label on (prime suspect: me, usually!) will be publicly embarrassed and a maintainer will quickly add the right label.

I'll leave it to Frank and other implementers to say whether it's actually been helpful in cutting down the noise, but anecdotally I've been hearing fewer complaints since we started doing this so 🀷.

03:32
<Jack Works>
spec 13.5.1.2 RS: delete operation
03:32
<Jack Works>
what does it mean by delete binding?
03:32
<Jack Works>
var a = '1'
delete a;
function z() { 'use strict'; a }
z()
03:33
<Jack Works>
I tried this but z didn't throw
04:03
<legendecas>
IIUC var declaration is not deletable (except in eval mode), so a is actually still reachable in z.
04:05
<legendecas>
https://tc39.es/ecma262/#sec-globaldeclarationinstantiation 16.1.7 step 17, defined as Perform ? env.CreateGlobalVarBinding(vn, false).. the second parameter of CreateGlobalVarBinding defines if the binding is deletable.
04:08
<Jack Works>

I got it.

a = '1'
delete a;
function z() { 'use strict'; a }
z()
04:08
<Jack Works>
this will throw
08:48
<Rob Palmer>
plenary will start in... 12 mins
09:08
<bakkot>
can someone remind me what the motivation for boxes is
09:08
<HE Shi-Jun>
allow to keep mutable object in record/tuple
09:09
<HE Shi-Jun>
I guess
09:09
<Ashley Claymore>
not just mutable, but also objects like functions
09:10
<bakkot>
if you can put a box in a record, you have already given up on the "records are deeply immutable" goal, so what benefit does the box have?
09:11
<Ashley Claymore>
Boxes are imutable. They are similar to having a Symbol
09:11
<Ashley Claymore>
and that symbol can be used to look up an object
09:11
<shu>
that seems to be a technical point
09:11
<shu>
conceptually it's to link the immutable to a mutable thing, right?
09:11
<bakkot>
they can be used to look up an object without any other facilities
09:11
<bakkot>
that sure does not sound like they are immutable to me
09:12
<bakkot>
like, they give access to mutability
09:12
<shu>
they're immutable in the sense that const is constant
09:14
<Mathieu Hofman>
There are a lot of use case that require expressing an immutable structure with mutable exit points
09:14
<Justin Ridgewell>
They give an explicit signal when leaving the immutable part of the "graph"
09:14
<bakkot>
Mathieu Hofman: right, but just putting an object in the record is already an immutable structure with mutable exit points
09:14
<bakkot>
how is "and then this value is not a primitive" not already an explicit signal?
09:15
<bakkot>
like, that is currently already how you distinguish between the mutable and the immutable stuff
09:15
<rbuckton>
Is there a reason this can't be solved using Symbol and Map?
09:15
<shu>
well, weakmaps i guess
09:16
<shu>
but i thought the R&T champions have gone back and forth on Box vs that approach
09:16
<Mathieu Hofman>
how is "and then this value is not a primitive" not already an explicit signal?
because you can't put non primitives inside records and tuples.
09:16
<shu>
i forget the outcome
09:16
<shu>
Mathieu Hofman: yes, but that's a design choice they made, which they now seek to introduce a new exit point for via a new primitive whose sole purpose is to wrap an Object
09:16
<shu>
seems... unnecessary, is how i read bakkot's point
09:17
<Mathieu Hofman>
There is a long discussion on why implicitly allowing objects inside records/tuples is not feasible
09:17
<Mathieu Hofman>
main one being it's a footgun
09:17
<shu>
why is this less a footgun?
09:18
<Mathieu Hofman>
because you need to explicitly wrap the object
09:18
<Mathieu Hofman>
you can't mistakenly put something mutable in your immutable structure
09:18
<shu>
but unless you're constructing all values inline, you could get a box already via a variable, no?
09:18
<Mathieu Hofman>
const tuple = #[getFoo()]
09:19
<shu>
getFoo() can return boxes, no?
09:19
<Mathieu Hofman>
it can, but you may not always know what it returns
09:19
<shu>
well yes, that's the point
09:19
<shu>
if it returns boxes, then #[getFoo()] is conceptually not deeply immutable
09:20
<shu>
but you don't know if getFoo() returns boxes or not
09:20
<shu>
so you don't know if #[getFoo()] is really deeply immutable without exit points or not
09:20
<nicolo-ribaudo>
The only way you get immutability is via a function call, like ObjectPlaceholder.unwrap(myBox): it's a function call that returns a mutable thing
09:20
<nicolo-ribaudo>
Exactly as if you would have a symbol representing an object, white a side symbol->Object map
09:21
<legendecas>
it can, but you may not always know what it returns
we cannot always know a function returning any type of thing, in that sense?
09:23
<bakkot>
boxes do not seem like a good fit for the thing justin is discussing? it seems like you would just want a #[type: 'user data', data: whatever]
09:23
<shu>
i missed the use case
09:23
<shu>
is it like taint tracking?
09:24
<Mathieu Hofman>
boxes do not seem like a good fit for the thing justin is discussing? it seems like you would just want a #[type: 'user data', data: whatever]
They can be leveraged to build that thing
09:25
<Justin Ridgewell>
I outlined it in the primitive issue
09:25
<Mathieu Hofman>
i missed the use case
It basically similar use case of marking exit points where value in the exit points can be any value (primitive or object)
09:25
<shu>
ah
09:26
<shu>
and ObjectPlaceholder doesn't work for that only because it can't contain primitives
09:26
<Justin Ridgewell>
https://github.com/tc39/proposal-record-tuple/issues/258#issuecomment-940639809
09:27
<Justin Ridgewell>
I'm annoyed that it's ObjectPlaceholder, but the reply in TCQ was to address why an explicit exit marking is valuable
09:28
<HE Shi-Jun>
The primitive issue could be solved by another layer of object, do I understand that correct?
09:28
<bakkot>
I am still really confused by what boxes are for
09:28
<bakkot>
is there an explainer somewhere?
09:29
<nicolo-ribaudo>
The primitive issue could be solved by another layer of object, do I understand that correct?
Yes, or #{ isObject: boolean, value: primitive | placeholder }
09:29
<bakkot>
specifically, the advantage of boxes vs just putting objects directly in the graph, and having "it is not a primitive" be the explicit exit point
09:30
<Justin Ridgewell>
But there's no need for that?
09:31
<Justin Ridgewell>
I havne't seen a justification for why we should prevent primitives directly in Box
09:31
<nicolo-ribaudo>
is there an explainer somewhere?
We have a short usage example at https://github.com/tc39/proposal-record-tuple#box (which uses Box as the name)
09:31
<bakkot>
that does not explain the motivation over just putting objects directly in the record
09:32
<HE Shi-Jun>
specifically, the advantage of boxes vs just putting objects directly in the graph, and having "it is not a primitive" be the explicit exit point
I remember the author of scala.js prefer just putting objects :)
09:32
<HE Shi-Jun>
I havne't seen a justification for why we should prevent primitives directly in Box
maybe it looks more "clear" ?
09:32
<nicolo-ribaudo>
that does not explain the motivation over just putting objects directly in the record

Ok, I always interpret "why we need placeholders" as "why just primitives isn't enough" πŸ˜…

We have https://github.com/tc39/proposal-record-tuple/issues/206 where we discussed about explicit/implicit boxing

09:33
<bakkot>
nicolo-ribaudo: again, the question is "why have boxes at all, vs just putting things in the graph directly"
09:34
<bakkot>
that issue presupposes the existence of boxes
09:34
<HE Shi-Jun>
Could we split objectplaceholder/box into further proposal? Consdier it could be implemented by symbol as weakmap keys?
09:35
<Ashley Claymore>
CompositeKeys for Maps is a key use case for Tuples, which i think a lot of people will want
09:35
<Ashley Claymore>
So I don't think this is a niche use-case, to want objects in Tuples
09:35
<bakkot>
right, but again, my question is "why not just put objects in tuples, instead of having boxes"
09:36
<HE Shi-Jun>
right, but again, my question is "why not just put objects in tuples, instead of having boxes"
good question. actually I also think maybe it's much fit for js? consider other similar languages also choose that way?
09:41
<shu>
So I don't think this is a niche use-case, to want objects in Tuples
this is probably the underlying question
09:41
<shu>
do the R&T champions think mutable exit points is common? if so, then why not bakkot's suggestion? if not, then why not symbols (technical problems notwithstanding)
09:42
<shu>
so far i've heard one argument against "why not bakkot's suggestion" is the need for primitive mutable exit points as well
09:43
<shu>
but then again the current solution also doesn't admit that
09:43
<Mathieu Hofman>
As I mentioned, there are a lot of issues with direct objects inside primitives. One was it's a footgun, and a user might mistakenly put mutable data where they didn't expect it. The other is the same security concern as how to "dereference" an ObjectPlaceholder. Existing code assumes that if something is a primitive, it doesn't contain object which represent authority. It would break a lot of deployed membranes and SES.
09:43
<HE Shi-Jun>
Maybe we need two things: Tuple (which could include object directly) and PrimitiveTuple
09:44
<shu>
Mathieu Hofman: i remain baffled by the footgun argument
09:44
<shu>
if it's common, you're asking people to look up incantations to do what they want
09:45
<HE Shi-Jun>
The other programming experience may not support footgun argument. Though JS may be have something special I don't know...
09:45
<bakkot>

One was it's a footgun, and a user might mistakenly put mutable data where they didn't expect it

Boxes don't really help that, since #[foo()] may or may not be a box and so may or may not be mutable. Also boxes are super complicated so it seems like there's at least as much possibility for footguns there

Existing code assumes that if something is a primitive, it doesn't contain object which represent authority.

But boxes are primitives which contain objects; this argument confuses me

09:45
<Mathieu Hofman>
if it's common, you're asking people to look up incantations to do what they want
I'm not following
09:46
<HE Shi-Jun>
Yeah, I remember the author of scala.js also point out some footgun of using Box in the issue.
09:46
<shu>
if wanting objects-as-mutable-exit-points-in-records is a common use case, i assure you people will do what they want to do, and just look up the incantation to do that. in that light, i'm not too convinced that you've avoided any footguns
09:47
<HE Shi-Jun>
So I am also not sure whether box could really solve the "footguns" of object in tuples.
09:47
<shu>
  • what's already been said about not knowing the return type of foo()
09:47
<Mathieu Hofman>

But boxes are primitives which contain objects; this argument confuses me

But you need access to the ObjectPlaceholder to get to the content, so they are not a risk on their own

09:47
<shu>
lol why does element convert + to a single bullet point list
09:48
<HE Shi-Jun>

But boxes are primitives which contain objects; this argument confuses me

But you need access to the ObjectPlaceholder to get to the content, so they are not a risk on their own

eventually developer would like to write some conditional logic and it could cause footgun in some way... as the author of scal.js shows.
09:48
<Mathieu Hofman>
if wanting objects-as-mutable-exit-points-in-records is a common use case, i assure you people will do what they want to do, and just look up the incantation to do that. in that light, i'm not too convinced that you've avoided any footguns
At least they've thought of it and the incantation is an explicit marker in the code
09:49
<rbuckton>
https://github.com/rbuckton/proposal-regexp-features/issues/2
09:49
<Mathieu Hofman>
Basically ObjectPlaceholder is a standardized "Symbol as weakmap key + global (per realm) weakmap registry"
09:51
<shu>
i would still like to know the "how common a use case do you expect mutable exit points to be" question
09:52
<Mathieu Hofman>
eventually developer would like to write some conditional logic and it could cause footgun in some way... as the author of scal.js shows.
I did not see any footgun in that example
09:53
<nicolo-ribaudo>
i would still like to know the "how common a use case do you expect mutable exit points to be" question
We initially didn't consider it, but after some users come up with the question "why only primitives?" (https://github.com/tc39/proposal-record-tuple/issues/31) we have started talking about it and found that users would love to be able to store objects because many things are not representable as immutable (for example, everything that comes from the dom)
09:53
<HE Shi-Jun>
I did not see any footgun in that example
Actually in the thread there are some code example to deal with box conditionally and have bugs, which seems a signal of footgun.
09:54
<Mathieu Hofman>
Agoric has discovered a strong need for records/tuples in order to make sure a Proxy can't be used to interleave code while traversing an apparently inert (deeply frozen) object. All these records do need to contain exit points (proxies/references to remote objects)
09:54
<erights>
Basically ObjectPlaceholder is a standardized "Symbol as weakmap key + global (per realm) weakmap registry"
Seeing it explained this way would be illuminating.
09:55
<shu>
okay, thanks for the anecdotes
09:56
<bakkot>
I have extremely strong reservations about making this be per-realm just for agoric's use case.
09:57
<Mathieu Hofman>
I have extremely strong reservations about making this be per-realm just for agoric's use case.
This is not just for agoric's use case, this is for any cross realm membranes
09:57
<Robin Ricard>
shu: the original need for boxes came up from framework authors, the ability to reference functions (handlers) in R&T seems essential if they want to be able to use R&T instead of objects
09:57
<Robin Ricard>
same with dom elements
09:57
<HE Shi-Jun>
I have extremely strong reservations about making this be per-realm just for agoric's use case.
it's ses use cases if i understand correctly...
09:57
<bakkot>
ok, same comment but with "just for existing cross realm membranes"
09:58
<Mathieu Hofman>
actually for agoric, it's not a problem if an ObjectPlaceholder can only be created explicitely
09:58
<legendecas>
so we will end 35 minutes early in the morning?
09:58
<shu>
+1 to bakkot
09:58
<shu>
and by "framework authors", is it react, or multiple frameworks?
09:59
<HE Shi-Jun>
react and many react-like frameworks I guess πŸ˜…
10:00
<shu>
to clarify my +1: i personally would give mid-weight to frameworks' need, especially if it extends beyond just one, and would give no weight to membrane enablement
10:00
<Michael Ficarra>
"we will add it because it exists elsewhere" is such a terrible argument
10:01
<bakkot>
yeah especially with regexes becauses everyone in the world has just copied Perl, which put everything anyone ever thought of into their regexes
10:01
<Mathieu Hofman>
to clarify my +1: i personally would give mid-weight to frameworks' need, especially if it extends beyond just one, and would give no weight to membrane enablement
This is not enablement, this is actually breaking security expectations of exiting deployments
10:02
<shu>
but side tables (again, with the symbol technical issues notwithstanding) also work for agoric, right?
10:02
<Michael Ficarra>
"I'd have to remember this (?=\R?\z) pattern" isn't much different than "I'd have to remember the difference between \z and \Z", except the former reads easier
10:02
<HE Shi-Jun>
One way to avoid the footgun of storing object in tuples maybe, make it explicitly, not by "box", but by "key"? for example only special key could store object: #{a: 1, &onclick: ()=>{} }
10:03
<Jack Works>
For the JSX use case, my first thought was: so R&T should be compared by value, _but_ treat all box as the same, otherwise it's not likely to speedup vdom based frameworks because most people don't write "useCallback" for their callback then the JSX record will always !==, Then the framework has to do the old classic diff algorithm and gain nothing from adopting record and tuple.
10:03
<Mathieu Hofman>
The main issue with symbol and side tables is being able to detect and target where the exit points are. It becomes an ergonomics issue of using them
10:03
<shu>
Jack Works: R&T is not likely to speed up vdom at all in any world
10:04
<Rob Palmer>
At the end of this session I've scheduled 5mins to discuss this clarification to the agenda deadline rule that Jordan talked about in this channel a week or so ago https://github.com/tc39/agendas/commit/d2ef80976759f763eaf621b851479753e29b081c#diff-0b87e2fc7748588525a23909f36542c8244da7bf86fe1e93ee9715e549f7944b
10:04
<Jack Works>
Jack Works: R&T is not likely to speed up vdom at all in any world
I know. Just my first thought when I see that use case.
10:06
<shu>
that seems like the best possible fix!
10:07
<Jack Works>
And I have another question. Months ago, Record and Tuple decides to use Symbols as WeakMap keys as the solution of storing objects. Why we have Box now?
10:08
<nicolo-ribaudo>
Because we found opposition against symbols as weakmap keys because of registered symbols (wich could never be collected)
10:08
<Jack Works>
Is that really a problem?
10:08
<Jack Works>
Set object on the global this can get the same result
10:09
<Mathieu Hofman>

2 main reasons:

  • Leaking issues with well-known and registered symbols
  • Box is an explicit marker of intent, where symbol can be just other data. You don't need knowledge about the structure to understand what it means
10:09
<HE Shi-Jun>
Because we found opposition against symbols as weakmap keys because of registered symbols (wich could never be collected)
what is registed symbols?
10:09
<nicolo-ribaudo>
Set object on the global this can get the same result
No, because the global can still be collected (when it's realm is collected)
10:09
<Jack Works>
No, because the global can still be collected (when it's realm is collected)
But WeakMap itself can be collected too
10:09
<Mathieu Hofman>
what is registed symbols?
Symbol.for()
10:10
<nicolo-ribaudo>
But WeakMap itself can be collected too
(I made the same point in the past, it wasn't me who didn't want symbols as weakmap keys πŸ˜…)
10:10
<HE Shi-Jun>
Sorry I don't understand leaking issues, is there any link to explain that?
10:11
<Jack Works>
Oh so is that means the Symbols as WeakMap key proposal is dead?
10:11
<Mathieu Hofman>
https://github.com/tc39/ecma262/issues/1194
10:12
<HE Shi-Jun>
so why not throw type error if weakmap meet a registed symbol?
10:12
<Mathieu Hofman>
If Box / ObjectPlaceholder exists, there is no need for symbols as weakmap keys, and the same semantics can be accomplished by creating a box of an empty meaningless object
10:13
<Mathieu Hofman>
so why not throw type error if weakmap meet a registed symbol?
there is opposition to that because it'd require users to understand the difference between registered and unique symbols
10:14
<nicolo-ribaudo>
If Box / ObjectPlaceholder exists, there is no need for symbols as weakmap keys, and the same semantics can be accomplished by creating a box of an empty meaningless object
Exactly, they are two alternatives that unlock the same unsecases
10:14
<Mathieu Hofman>
MM gave a great summary
10:14
<Jack Works>
So R&T is the only use case for that?
10:15
<HE Shi-Jun>
there is opposition to that because it'd require users to understand the difference between registered and unique symbols
good point, though I don't think it's a big problem, if symbol as weakmap is mainly used to implement box as low-level mechanism.
10:15
<Mathieu Hofman>
So R&T is the only use case for that?
definitely not, ShadowRealm based membranes are also a primitive in weakmap use case, but as I mention just above, you can accomplish the same with Box
10:17
<bakkot>
i don't hate this proposal, but also this seems like one of those things which ~zero people are going to use until after they get the CVE
10:18
<Jack Works>
LOL
10:18
<bakkot>
regexes are already too complicated for most people to figure out if they're going to have catastrophic backtracking and this proposal proposes to solve that by making them more complicated
10:18
<bakkot>
so tbh I feel like the "so then they had to rewrite without a regex" is not so bad
10:19
<Jack Works>
Alt: research how to teach regexp systematically
10:19
<HE Shi-Jun>
i don't hate this proposal, but also this seems like one of those things which ~zero people are going to use until after they get the CVE
even they get CVE, I guess they will not use feature but just write a special function to trim end newlines...
10:21
<Justin Ridgewell>
For Waldemar's question: It's impl defined? If it sees \n++$, and that didn't match, the impl can advance 100k chars, then restart trying
10:27
<Michael Ficarra>
I hate how all these regexp proposals are phrased in terms of a feature and not a problem we're trying to solve
10:27
<Michael Ficarra>
I'm fine for stage 1 for looking into catastrophic backtracking issues, but not okay with committing to this solution, which is how I know it will be mistaken
10:30
<msaboff>
The atomic operators appears to be a new "middle" counting type.
10:30
<msaboff>
A greedy non-backtracking type.
10:30
<waldemar>
The description of backtracking was too terse. Does "(?>...) will not backtrack in the event of a failed match" mean that it turns off backtracking internally only when going into or out of the group?
10:31
<waldemar>
When does backtracking reset for ++?
10:31
<msaboff>
For the example /[\r\n]+$/, using the non-greedy quantifier (/[\r\n]+?$/) also solves the O(N^2) case.
10:31
<rbuckton>
A fair amount of the regexp problem space is a known quantity given the broad adoption across multiple languages and runtimes. The biggest issue with catastrophic backtracking is that its not an easy to solve problem. Perl has a significant amount of additional backtracking control verbs over what I've proposed.
10:32
<waldemar>
What is going on in the 100,000 newlines example? Both backtracking and nonbacktracking should be O(nΒ²) if the description is correct. However, such a huge difference in running time means something else is going on.
10:32
<rbuckton>
Most of which I would consider to be "far to complex" to add to the language.
10:33
<msaboff>
My concern is that the developer doesn't understand the full implications of the backtracking control. It is an implementation detail (currently shared among most implementations), that they likely get wrong.
10:33
<waldemar>
Typo: Does "(?>...) will not backtrack in the event of a failed match" mean that it turns off backtracking internally or only when going into or out of the group?
10:34
<msaboff>
It would have to be just for that group.
10:35
<waldemar>
What happens if you have something like /a*(?>...)/? Does the ?> lock in the first time it fails and not try some other match with a different number of a's?
10:35
<Michael Ficarra>
how would we even go about specifying the backtracking control if we don't specify the regexp evaluation mechanics?
10:37
<rbuckton>
We do specify RegExp evaluation semantics
10:37
<Michael Ficarra>
rbuckton: and those semantics necessitate catastrophic backtracking today?
10:37
<rbuckton>
Quantifiers are specified here: https://tc39.es/ecma262/#sec-runtime-semantics-repeatmatcher-abstract-operation
10:37
<Michael Ficarra>
I don't think so
10:38
<msaboff>
The trailing ? is really {0.1} and therefore it should backtrack, but not the (?>...) itself. I think this requires saving the state of the (?>...) for the trailing ? backtracking.
10:38
<bakkot>
we specify as-if semantics, which does not correspond to what engines actually do
10:38
<Michael Ficarra>
exactly, so I again ask how we would specify this feature
10:38
<bakkot>
we do not currently put any execution time constraints on regex performance
10:39
<Michael Ficarra>
exactly, so I again ask how we would specify this feature
10:39
<waldemar>
For the example /[\r\n]+$/, using the non-greedy quantifier (/[\r\n]+?$/) also solves the O(N^2) case.
It's a failed match, so greedy or nongreedy shouldn't make any difference β€” they both must check all possibilities, they just do it in the opposite order. Of course that assumes no hidden implementation optimizations that somehow apply to one and not the other.
10:40
<rbuckton>
Michael Ficarra: Specifying Possessive would likely be the similar to specifying Greedy in RepeatMatcher.
10:40
<Justin Ridgewell>
It's a failed match, so greedy or nongreedy shouldn't make any difference β€” they both must check all possibilities, they just do it in the opposite order. Of course that assumes no hidden implementation optimizations that somehow apply to one and not the other.
The impl can advance beyond the non-match
10:41
<waldemar>
Huh?
10:41
<Justin Ridgewell>
It doesn't have to check index 1, 2, 3, 4, etc
10:41
<msaboff>
It's a failed match, so greedy or nongreedy shouldn't make any difference β€” they both must check all possibilities, they just do it in the opposite order. Of course that assumes no hidden implementation optimizations that somehow apply to one and not the other.
In the non-greedy case, I don't think you back track each character.
10:41
<waldemar>
In order to get a non-match, it must check all possible lengths of [/r/n]+.
10:41
<Justin Ridgewell>
It tried 100k chars, didn't match, advance 100k chars
10:41
<waldemar>
That's what I was asking Ron about.
10:42
<waldemar>
The answer I got at the meeting was that it would retry for each starting index.
10:42
<waldemar>
If that's not what it's doing, then what it is doing needs to be described better.
10:43
<rbuckton>
I will expand on the proposal for a future meeting, with more details on matching behavior (and possibly a prospective spec) to clarify matching behavior.
10:45
<waldemar>
The other alternative is that there is some secret optimization that triggers based on regular expression minutiae, and the ++ version just happens to trigger the secret optimization even though it should still be O(nΒ²). If that's the case, then an implementation could choose to apply the same optimization to the original version too.
10:45
<shu>
fwiw V8 implemented an explicit opt in "linear mode" via a flag
10:45
<shu>
but experiment didn't pan out
10:45
<shu>
among other things, the technical challenges to performantly switch between modes were many and difficult to solve
10:46
<Michael Ficarra>
oh interesting, I didn't even consider the possible implementation difficulties for this feature
10:46
<shu>
(but i also don't know any more details, not my area of expertise)
10:47
<bakkot>
does v8 currently have someone working specifically on the regex engine you could float this by?
10:47
<shu>
irregexp is in maintenance mode, but we have someone who knows enough to add new features
10:47
<shu>
i will certainly float this by them
10:48
<bakkot>
someone is... playing music?
10:48
<bakkot>
is that just me hearing this
10:48
<Michael Ficarra>
Justin Ridgewell: ^
10:48
<ryzokuken>
funky music
10:49
<Justin Ridgewell>
I'm muted?
10:49
<msaboff>
In the non-greedy case, I don't think you back track each character.
I checked in JSC and /[\r\n]+$/ takes 11 seconds and /[\r\n]+?$/ takes 7 seconds. Looks like /[\r\n]+$/ is O(2n^2) and /[\r\n]+?$/ is O(n^2). So still n^2.
10:49
<Michael Ficarra>
I'm muted?
now you are
10:49
<Michael Ficarra>
I'm assuming a chair muted you
10:49
<Justin Ridgewell>
Oh, but I've got no music.
10:50
<bakkot>
now someone is doing dishes
10:50
<Michael Ficarra>
strange, maybe Jitsi was misattributing the noise to you
10:50
<shu>
is someone cooking now
10:50
<msaboff>
Breakfast?
10:50
<shu>
sounds like dishwasher
10:50
<shu>
loading dishwasher rather
10:51
<ryzokuken>
it was sarahghp muted you Sarah πŸ˜€
10:51
<msaboff>
The kitchen is closed!
10:51
<ryzokuken>
no more dishes for you πŸ˜›
10:53
<sarahghp>
I'm so sorry. I never explicitly unmuted, so I dunno. It was unloading.
11:07
<Sergey Rubanov>
BTW wasm CSP was promoted from phase 1 to phase 3 (implementation phase) two days ago https://github.com/WebAssembly/meetings/blob/main/main/2021/CG-10-26.md (notes are not published yet)
11:09
<Michael Ficarra>
did I miss "Agenda deadline rule clarification"?
11:10
<bakkot>
no, we haven't done that yet
11:22
<jschoi>
Are there still plans to have a CoC Committee update?
11:33
<ryzokuken>
jschoi: most likely not, unfortunately.
11:42
<Rob Palmer>
did I miss "Agenda deadline rule clarification"?
no - I'll do it first thing after the break
11:43
<Rob Palmer>
(or Jordan can!)
11:59
<Rob Palmer>
we are starting in 1 minute
12:02
<Justin Ridgewell>
Auto-merge bot for TC39 org members
12:03
<ljharb>
Rob Palmer: i would like the opportunity to discuss evaluator attributes still, there's a reason it was a schedule constraint
12:04
<bakkot>
you can just merge your own PRs
12:04
<bakkot>
don't need a bot
12:04
<Justin Ridgewell>
Ahh
12:06
<Michael Ficarra>
I feel like it's painfully obvious that a PR is sufficient for this requirement
12:07
<jschoi>
Slides for next presentation are at https://docs.google.com/presentation/d/1MShu-uA_gz1LDpmlckQ9Wgsb0ZLylYV0QWZBnsTAOGk/edit?usp=sharing.
12:08
<shu>
the history of the agenda repo is just "Update"
12:08
<ljharb>
Rob Palmer: I can try to give a brief CoC update as well, whenever
12:09
<Rob Palmer>
Rob Palmer: i would like the opportunity to discuss evaluator attributes still, there's a reason it was a schedule constraint
we have 10 mins at the end - Guy suggested it too
12:11
<Michael Ficarra>
I completely disagree with the point on the slide that identity could ever be clearer than x => x
12:12
<bakkot>
extremely strong +1
12:12
<shu>
i disagree more strongly with constant(x) over () => x
12:12
<Michael Ficarra>
shu: it'd be x => () => x
12:13
<shu>
wat
12:13
<shu>
that wouldn't be what constant(x) returns
12:13
<shu>
that's how you would define constant
12:13
<Michael Ficarra>
no I mean that'd be constant
12:13
<bakkot>
right but instead of constant(x) you should write () => x, is the point
12:13
<Michael Ficarra>
oh I see what you mean, you mean replacing that whole expression with the arrow
12:14
<Michael Ficarra>
... what's a "fluture"?
12:15
<bakkot>
fantasyland promise
12:15
<ljharb>
i have certainly made a thunk helper that is x => () => x, but i don't think that needs to be in the language
12:16
<yulia>
I don't think this needs to be in the language
12:16
<bakkot>
uncurryThis should be though
12:16
<bakkot>
and I could see flow, maybe
12:17
<Michael Ficarra>
flow (function composition) is interesting, but I think it being single-parameter makes it kinda awkward for JS
12:17
<bakkot>
once, also
12:17
<Michael Ficarra>
once is great, I write once all the time
12:17
<shu>
how... can we specify debounce?
12:17
<Michael Ficarra>
and it's annoying
12:17
<bakkot>
debounce and throttle don't work without time though, which probably don't belong in JS
12:17
<shu>
yeah these can't be in 262
12:18
<bakkot>
HTML would probably add them if you asked them to though
12:18
<Michael Ficarra>
I'm thinking these should be split into separate proposals because many of them clearly don't stand on their own
12:18
<yulia>
yes
12:19
<yulia>
i don't think we should encourage this kind of approach to proposals -- we should work with concrete problem statements rather than giving an arbitrary blank check on "we will add function helpers"
12:20
<shu>
+1 to more scoped problem statement
12:21
<bakkot>
yeah, I like really lightweight proposals
12:22
<bakkot>
like, flow and flowAsync belong in the same proposal, but neither obviously belongs in the same proposal as uncurryThis or once
12:22
<yulia>
yes
12:22
<bakkot>
I don't want to talk though
12:22
<bakkot>
someone maybe could put this on the queue
12:26
<bterlson>
ptomato: you ready for temporal overflow in a few mins?
12:27
<rbuckton>

Over the break I read and reread RepeatMatcher, but I don't think I'm incorrect in my understanding of backtracking. For /\n+$/.test("\n".repeat(100_000) + "b") we end up in a stack 100,001 calls to RepeatMatcher deep before we (a) fail to match an \n and then (b) fail to match the end of the buffer. We then unwind the stack, attempting to match the end of the buffer for each entry on the stack. This means we test for $ at offset 100,000, then at 99,999, then 99,998, etc. until we fail at offset 0 (matching no \n characters).

Now that this has failed, we advance to the next index in RegExpBuiltInExec, and do it all over again.

12:27
<ryzokuken>
ptomato: you ready for temporal overflow in a few mins?
justingrant: ?
12:28
<justingrant>
Yep!
12:28
<justingrant>
@ptomato should be on shortly
12:29
<justingrant>
I'm presenting today (only 2 slides)
12:29
<Michael Ficarra>
rbuckton: The spec doesn't mandate that you implement in that way if it's not observable
12:29
<ryzokuken>
Jack Works: you have some music in the background
12:30
<rbuckton>
Michael Ficarra: True, but my point is that backtracking retries the pattern to the right of the quantifier for each possible choice of repeated \n characters, starting with the largest.
12:32
<rbuckton>
There are possible optimizations if the remaining pattern is a fixed length set of characters, if the Atom being repeated could not be matched by the continuation, but a regexp can easily be crafted that breaks those optimizations.
12:33
<Michael Ficarra>
rbuckton: so you're saying any implementation of a JS regexp matcher today necessarily has catastrophic backtracking?
12:34
<rbuckton>
Why would we block time-related functions? We have to have time-awareness in JS for Atomics.wait or Atomics.waitAsync. I think a Promise.delay polyfill could be built purely on top of waitAsync without depending on the DOM Timers API.
12:34
<ljharb>
doesn't Atomics only wait for something in another thread to make a change in a SAB? that's not involving time
12:35
<shu>
there's a timeout
12:35
<ljharb>
ah
12:35
<ljharb>
erights: the timeout in Atomics.wait isn't an issue?
12:35
<rbuckton>
You can use Atomics.wait to emulate sleep in NodeJS or in a Web Worker.
12:35
<shu>
my concern isn't any SES concern to be clear
12:36
<shu>
i don't think the value add is enough to add more fairly heavyweight hooks to the spec to queue tasks
12:36
<shu>
if we want these just add these to html
12:36
<shu>
have node implement them
12:37
<shu>
Atomics.wait's timeout is special in that the waiting thread is literally blocked
12:37
<shu>
Atomics.waitAsync's timeout is more analogous
12:37
<rbuckton>
IMO, I'm not too enthusiastic about debounce/throttle, as a purpose-built solution can be more flexible (sliding windows, minimum/maximum delays, etc.)
12:38
<shu>
good to know
12:38
<ljharb>
with throttle, most use cases run the function after the window, but some want to silently drop instead, so to standardize we'd have to have a way to allow both
12:39
<bakkot>
lack of standardization in existing methods is arguably a good reason to have it in the platform
12:39
<Michael Ficarra>
what's the chance that Temporal is bug-free by the time it hits stage 4? 0? I think 0.
12:39
<bterlson>
Michael Ficarra: Is it not true that given the features we have and the semantics we want (e.g. best match), you can craft a regexp with "catastrophic" behavior, and doing that pattern non-catastrophically would result in observably different semantics in some cases? I thought I learned this at one point.
12:40
<ljharb>
i don't think any userland implementation i've seen commonly used implements the drop use case. but someone asked about it in a chatroom just the other day
12:40
<Michael Ficarra>
bterlson: I'm not sure. I want to know this.
12:41
<ljharb>
you can absolutely craft a regex that hangs v8 but not spidermonkey, and have been able to for many years; not sure if that's the question
12:41
<Michael Ficarra>
ljharb: not talking about existing implementations, talking about theoretical implementations
12:41
<shu>
how can that be possible
12:41
<shu>
SM switched to irregexp
12:41
<ljharb>
oh maybe it hangs spidermonkey now, i haven't checked
12:42
<bakkot>
I feel like I read something recently about an engine which after a while switches to an implementation which is slower in common cases but guaranteed not to be catastrophic
12:42
<bakkot>
but maybe that was not JS
12:42
<shu>
that's what linear mode turned out to be, but we're not going to ship it
12:43
<shu>
not sure if you're thinking of linear mode
12:43
<bakkot>
oh, got it
12:43
<bakkot>
probably am
12:43
<shu>
it was an intern project to add a new flag that opts into a linear only, no backtracking regexp engine
12:43
<bterlson>
I also think that's only true in theory with like infinite memory, and also might not work with e.g. backrefs or other non-regular features?
12:43
<yulia>
oh maybe it hangs spidermonkey now, i haven't checked
oh that would be weird, we use v8's regexp engine
12:43
<bterlson>
(or without preserving ES best match semantics)
12:44
<Justin Ridgewell>
Best match isn't the issue
12:44
<Justin Ridgewell>
It's just the backreferences and unbounded look-arounds
12:44
<Justin Ridgewell>
It's not possible to implement all the required features without using a backtrack impl
12:44
<Justin Ridgewell>
So everyone implements a backtrack impl
12:45
<Michael Ficarra>
thank you Justin Ridgewell that's what I was expecting
12:52
<bakkot>
https://v8.dev/blog/non-backtracking-regexp
12:52
<bakkot>
found the article I was thinking of
12:52
<bakkot>
relevantly, it only works in the absence of backrefs and lookarounds
12:55
<devsnek>
that engine could support backreferences with better average performance than irrgexp but they want to keep it separate
12:56
<jschoi>
Just making sure: There’s going to be a call for incubator topics at the end of the plenary, right?
12:56
<shu>
should be, yes
12:57
<shu>
ljharb: technically i could have Object.prototype.smallestUnit
12:58
<ljharb>
in that case {} wouldn't be an empty object
12:58
<ljharb>
i think we're using {} here to mean "an object for which a Get() of all relevant properties returns undefined", or similar
12:58
<ljharb>
({ x: 1 } would be an empty object wrt Temporal, eg)
12:59
<shu>
i mean it's not an empty object
12:59
<shu>
it's an object without the property, sure
12:59
<ljharb>
"an object empty of relevant temporal properties" is the case we're talking about, it's just longer to say
13:16
<shu>
ljharb: i feel very strongly in the opinion that wasm use cases at the boundary are JS use cases
13:16
<shu>
as is the case here
13:16
<ljharb>
it is clear that folks who are invested in wasm feel that way
13:17
<shu>
that's a gross mischaracterization
13:17
<bakkot>
do we take notes on COC report?
13:17
<bakkot>
I assume no?
13:17
<shu>
"folks who are invested" are like... several large multinational corporations with lots of product teams devoted to it?
13:17
<Jack Works>
erights: the timeout in Atomics.wait isn't an issue?
I thought there is no time in the ES spec until I see this Atomics.wait
13:17
<shu>
so it's not like a fringe group on the internet
13:20
<ljharb>
sure, no such "fringeness" was implied
13:21
<ljharb>
bakkot: high-level notes are fine, probably best not to include discussion of specific moderation actions
13:21
<bakkot>
ljharb: feel free to redact notes, we have a verbatim transcript as usual atm
13:21
<ljharb>
cool, will do
13:22
<jschoi>
Pipe group wants a pipe incubator call for bikeshedding the topic token.
13:31
<Michael Ficarra>
don't forget to review the notes!
14:05
<rickbutton>
happy end of plenary everyone, now go to sleep
14:05
<rickbutton>
:)
14:09
<Ashley Claymore>
don't forget to review the notes!
For anyone new to note-taking. I've been using https://rogueamoeba.com/audiohijack/ so I can pause/re-wind/jump-to-live the audio using global hotkeys. Which I've found makes bot-helping much less stressful.
14:11
<Ashley Claymore>
I did start trying to put something together with the WebAudio apis that could add a delay that I could use on windows but didn't get it to work with routing between different apps and outputs
14:11
<Ashley Claymore>
everytime I did a google for 'windows audio buffer delay utility' I just got results for how to fix my audio delay issues. Not introduce one on purpose
16:08
<rickbutton>
what kind of ExpressionStatment is the let [ negative lookahead trying to guard against? what expression starts with let [?
16:09
<rickbutton>
oh duh, let is a valid identifier in sloppy mode