| 00:56 | <Chris de Almeida> | WHO AMONGS'T'VE YOU IS WILLING TO STEP UP TO HELP WITH THE NOTES |
| 00:56 | <Chris de Almeida> | reveal yourselves |
| 01:25 | <bakkot> | this timebox is not going to be close to sufficient, though the schedule currently does have 30 minutes of free space this session |
| 01:28 | <Chris de Almeida> | true, but that's sort a false indicator that we can extend when we should not. we can do a continuation if we have time later |
| 01:35 | <rkirsling> | huh, didn't realize that was a way to remove an event listener |
| 01:37 | <Chris de Almeida> | which way specifically? |
| 01:37 | <rkirsling> | to pass an AbortSignal to addEventListener |
| 01:39 | <rkirsling> | I guess that would ease the burden of having to hold onto the reference to the handler so that you can remove it later? |
| 01:41 | <Lea Verou> | I'm kind of meta-excited about this proposal because of the precedent it establishes of pulling things in that should really have been in TC39 to begin with. What's next? 😀 Maybe import maps? 😀 The sky is the limit! 😀😇 |
| 01:43 | <Lea Verou> | (maybe this should have been posted in TDZ, not sure, still figuring out the split) |
| 01:45 | <rkirsling> | nah it's relevant to the current topic and not just a joke, so this is the right place |
| 01:47 | <Olivier Flückiger> | oh sure. the question is always, if the mere possibility of the uncommon case blocks optimizations, or if we can somehow speculate it out of the way. answer is not always clear, often it's a bit of both. |
| 01:49 | <Justin Ridgewell> | I literally wanted an abort signal in a Promise.all() earlier today. |
| 01:50 | <Justin Ridgewell> | And got around it by doing race([all(…), cancelablePromise]) |
| 01:56 | <Ashley Claymore> | I think signal to Promise.all makes sense. I just hope people don't read it as the signal magically being passed into the work that the promises represent. |
| 01:57 | <ljharb> | (some examples: abortcontroller, import maps, observable, structured clone…) |
| 01:57 | <peetk> | it's too bad <EOM> comes at the end of the message because it's clearly hard for chairs to catch it extemporaneously |
| 01:58 | <Ashley Claymore> | <NNTS>{msg}</NNTS> (no need to speak) |
| 01:58 | <Jesse (🇯🇵)> | <no-need-to-speak>+1</no-need-to-speak> |
| 01:58 | <Jesse (🇯🇵)> | jinx! |
| 01:58 | <Rob Palmer> | feel like sending a TCQ PR to add this as a structured field? |
| 01:58 | <Richard Gibson> | 🙊 |
| 01:59 | <Rob Palmer> | (I should say, anyone could do this) |
| 02:01 | <Ashley Claymore> | (👏 in room) |
| 02:01 | <Chris de Almeida> | that would be a good feature! |
| 02:03 | <rkirsling> | interesting, [(] as a way to avoid using a backslash in a regex |
| 02:03 | <bakkot> | I glossed over it briefly, but I do really think we're missing a way to unregister a .then call, and passing a { signal } argument does seem like the obvious way to do it if we have AbortSignal in the language |
| 02:04 | <bakkot> | for example, if you're doing a Promise.race, that adds handlers to all the Promises, and then those (per spec) all stick around until all the Promises have settled even though none of them do anything after the first |
| 02:04 | <rbuckton> | @erights Mark Miller (Agoric) MM: One of the original reasons for sync callbacks was related to this quote from Dean Tribble that is reposted in the README for the cancellation proposal:
Another reason for sync notification is that it ensures an entire cancellation graph can be set to the canceled/aborted state all at once, rather than incrementally as each notification triggers cancellation of a linked signal. |
| 02:04 | <bakkot> | in principle a really clever engine could optimize those out but no one does |
| 02:05 | <sffc> | As a note taker: There's a 5-10 second delay on the transcription bot, but rapid back-and-forths can have multiple changes of speaker within that time, and the transcription bot adds line breaks between speakers 80-90% of the time but not 100% of the time |
| 02:06 | <sffc> | The comments are sometimes one-word comments like "yeah" and "no" and "i guess" which have very different interpretations and seem important to attribute correctly but are sometimes difficult to hear |
| 02:07 | <rbuckton> | IMO, we should be able to pass a signal to new Promise(init, { signal }), Promise.prototype.then(onfulfill, onreject, { signal }) (and catch, finally), Promise.resolve(value, { signal }), Promise.all(iter, { signal }), and many other places. |
| 02:09 | <bakkot> | for the new Promise one, you can always just pass the signal to init directly, right? |
| 02:10 | <bakkot> | for Promise.resolve, you just mean that if value is a thenable it forwards the signal to value.then(f, r, { signal })? or something else |
| 02:10 | <bakkot> | but yes, agreed re then/catch/all` etc |
| 02:11 | <sffc> | I primarily use my ultra-short-term memory of the sound of the voice when attributing comments, but this isn't 100% accurate, so when it fails I fall back to context of the conversation, but that also isn't 100% accurate. |
| 02:11 | <Mathieu Hofman> |
|
| 02:12 | <sffc> | What would help for note-taking is if speakers could wait until the other speaker could finish a sentence, and speak in complete sentences. Mid-sentence breaks are the hardest to track |
| 02:12 | <bakkot> | Mathieu Hofman sometimes the thing that is scheduling work cannot be modified to read from the signal itself, and needs to be actively notified, which you do by adding an abort callback to the signal and having that callback notify the thing scheduling work |
| 02:13 | <rbuckton> | Passing the signal to new Promise itself allows the runtime to affect how .then registrations occur. Passing the signal to Promise.resolve() affects how it handles adoption of a Promise passed as the value. |
| 02:14 | <bakkot> | say more about "allows the runtime to affect how .then registrations occur"? |
| 02:14 | <bakkot> | (or feel free not to, I might forget by the time this becomes relevant again, which will be a while) |
| 02:18 | <rbuckton> | If you abort a signal attached to the promise constructor before any .then registrations are made, then you can immediately reject the promise from the outside and use the fast path for new registrations via .then (i.e., enqueue promise jobs directly rather than queuing them in [[PromiseFulfillReactions]]/[[PromiseRejectReactions]]). |
| 02:19 | <rbuckton> | Or, if we don't reject canceled promises, we can have a different fast path for never-resolving promises. It depends on what behavior we would adopt for .all, et al. |
| 02:23 | <rbuckton> | One of the big features I wanted for cancellation/abortcontroller was having a fast path to release memory held by closures: For a cancellation graph, a way to "close"/"dispose" the graph to indicate it will never be canceled, so registered callbacks can be dropped. For Promises, a way to propagate cancellation so that registered continuations can be dropped, though that depends on whether cancellation is silent (never resolves) or noisy (rejects). |
| 02:24 | <bakkot> | I think it's gotta reject, never-settling Promises are very bad |
| 02:25 | <rbuckton> | bakkot: We can maybe get around the DOMException thing by specifying that an ES AbortController must take a reason when you abort? DOM layering could make it optional and create DOMException in those cases. |
| 02:26 | <ljharb> | i'm confused how parsing bigint literals wouldn't be easier than parsing number literals, since fewer things are valid? |
| 02:29 | <Olivier Flückiger> | it's not immediately clear if the result will be integral |
| 02:29 | <Olivier Flückiger> | you first need to find the exponent |
| 02:29 | <Olivier Flückiger> | then depending on the exponent parse from the start |
| 02:29 | <ljharb> | ah so the issue isn't with the parsing exactly, it's that at the stage you'd want to early error, you haven't necessarily computed the numeric value yet? |
| 02:29 | <ljharb> | (meaning, with Number literals you don't have to compute the actual value until runtime?) |
| 02:30 | <Richard Gibson> | I generally find enclosing brackets to be more readable than backslash prefixes (and am aware that this is a minority preference) |
| 02:30 | <Jesse (🇯🇵)> | for negative exponents, a bit more work is required; but if only non-negative exponents are supported, I guess it should be fairly easy (comparing the length of the string before the e with the Number value of the exponent) |
| 02:31 | <rkirsling> | not sure about readability but I could see it being nice to avoid the situation where you need to escape a backslash |
| 02:31 | <Jesse (🇯🇵)> | I generally use [.] |
| 02:33 | <Chris de Almeida> | is there still popping sound on the audio for remote folk? |
| 02:38 | <rbuckton> | { objectPrototype: "null" | "default", arrayPrototype: "default" }, never give another option for arrayPrototype? |
| 02:40 | <sffc> | ljharb keith_miller your comments got merged together and I wasn't confident where to break them, ptal: JHD/KM mixed transcription: It's not necessarily that it has to be functionally identical. It's that it's a weird inconsistency if it can't be. I mean, how would you even how would it even make sense? No, that's what I mean. It wouldn't. But the. But then you can use it to the extent that it makes sense but you can't use it beyond the point that it makes sense. But like if you typed your import attribute and you put something that in code would reference an object like array.prototype or something, and then you get a SyntaxError. That's just weird and confusing, I think. And that doesn't come into play if it's a Boolean. |
| 02:45 | <rkirsling> | ljharb: can't "null object" just refer to null itself? |
| 02:46 | <ljharb> | i can see that reading, but no, because null is famously not an object despite what typeof says (like, it's probably one of the most known things about JS among practitioners) |
| 02:46 | <Mathieu Hofman> | Mathieu Hofman sometimes the thing that is scheduling work cannot be modified to read from the signal itself, and needs to be actively notified, which you do by adding an abort callback to the signal and having that callback notify the thing scheduling work |
| 02:46 | <bakkot> | that is one argument among several, yes |
| 02:56 | <Ashley Claymore> | Really cool to see all 3 major engines discuss and get consensus on that issue |
| 02:56 | <Richard Gibson> | ooh, or more legibly at small size: 😶 |
| 02:57 | <waldemar> | Heh, I just upgraded to Firefox 157 and now Google Docs gives me an infinite error loop when I try to access the notes. Not sure if the two are correlated., |
| 03:31 | <bakkot> | ooh, interesting thought. I think in practice it would be unfortunate if code could not rely on .abort() working? and checking for .name === 'AbortError' is a common pattern it would be nice to ensure people could keep using. but, something to consider, for sure |
| 03:58 | <Chris de Almeida> | taps the sign ☝️ |
| 04:02 | <waldemar> | Just a coincidence. Also started happening in Firefox 156 for our notes document. |
| 04:04 | <bakkot> | another important reason the callback needs to be sync is that cancellation fundamentally does not have anything to do with asynchronous code. it is entirely reasonable to have a purely synchronous code where you need to do cancellation; for example, you could have a task queue (of synchronous tasks) that various tasks push other tasks to, and you want the ability for one task to cancel specific other tasks sometimes (i.e., to remove them from the queue; if the tasks are themselves aware of the signal they can poll it once they're initiated if they remember to do so, but this now requires intrusive modifications and is also less efficient). AbortSignal is the natural way to do this. and since there is no async at all in this world, having cancellation be deferred to the next tick would make it totally useless. |
| 04:09 | <keith_miller> | bakkot: Our Web Platform folks ok'd moving AbortController, in theory. |
| 04:38 | <hax (HE Shi-Jun)> | I still worry about changing scoping rule, even it might be web compatible, such change will confuse AI agents at least some years~ 😅 |
| 04:39 | <ljharb> | bakkot: private #x is what's changing how #x = 2 works in the class body already (because it's not creating a brand new field, in that case) - so "changing how private fields work" is already true. what's wrong with removing the "duplicate field installation" error in that case also? |
| 04:45 | <bakkot> | In principle we could also make other changes, but I fought for duplicate installation being an error originally and I don't want to change it |
| 04:45 | <bakkot> | I think that that error is good |
| 04:45 | <waldemar> | Concatenating code was just an illustrative example; the scoping problem exists without naive concatenation. |
| 04:45 | <Justin Ridgewell> | I think this will be a bigger web compat risk |
| 04:46 | <ljharb> | it'd be new code, compat risk should be impossible |
| 04:46 | <ljharb> | right but that always exists for any bindings, no? |
| 04:46 | <Justin Ridgewell> | No, it'd fundamentally change class WeakMap { #inner = … } |
| 04:47 | <ljharb> | typing private #inner; already fundamentally changes it |
| 04:47 | <waldemar> | For lexically scoped bindings the problem doesn't arise. |
| 04:47 | <bakkot> | your proposal would either change the semantics of existing code, or would be making private #x a different kind of thing than existing private fields |
| 04:47 | <bakkot> | I really do not want to have two different kinds of private fields |
| 04:47 | <waldemar> | An outer scope can't pluck a variable out of an inner scope. |
| 04:48 | <ljharb> | it would change the semantics of #x = 1 from "error if the field is there, install the field, assign the field" to "install the field if it is not already there, assign the field". that's a pretty small change |
| 04:48 | <ljharb> | i understand you don't want it. but i don't think there's any technical reason we couldn't do it |
| 04:48 | <bakkot> | waldemar: my model is that this is still lexically scoped, it's just that, for convenience, class { #x } in a scope which doesn't already have one introduces the name into the class body's scope |
| 04:49 | <bakkot> | yes, it's a change we could make, but I agree with Justin Ridgewell that it's a much bigger web compat risk |
| 04:49 | <bakkot> | people are relying on that error |
| 04:49 | <ljharb> | something that requires new syntax can not possibly be a web compat risk. because no existing code uses private #x |
| 04:49 | <ljharb> | it could arguably be a refactoring hazard if they add that. but that's not "web compat" |
| 04:50 | <ljharb> | (and "refactoring hazard" might be a dealbreaker for it, sure - just clarifying "web compat") |
| 04:50 | <bakkot> | again, your proposal would change the semantics of existing code |
| 04:50 | <bakkot> | because existing code already has #x = 1 |
| 04:51 | <ljharb> | only when existing code is edited to add private |
| 04:51 | <ljharb> | and even as proposed, that DOES change the semantics of that existing code |
| 04:51 | <waldemar> | To make it lexically scoped, everyone would have to get into the habit of writing class { private #x; #x } instead of class {#x} whenever they're not using an outer-scope #x. |
| 04:51 | <ljharb> | it changes it from "make a new field" to "reuse the declared field". "changing the semantics of existing code when you type the new thing" is how every syntax proposal works, that's not "web compat" |
| 04:51 | <bakkot> | so your proposal is that fields declared with private #x would work differently than fields declared in the current way? that's the other arm of my fork above; I do not want to have two different kinds of private fields |
| 04:52 | <ljharb> | no, the field would work the same way. only the #x = 1 line in the class body, which is already doing something different, would do something else different |
| 04:52 | <ljharb> | once installed it's identical. the change i'm suggesting is only in the line that's creating and installing it on a class instance (which, your proposal already changes) |
| 04:52 | <bakkot> | right, so, you'd be changing the semantics of existing code, which can therefore be a web compat risk |
| 04:52 | <Justin Ridgewell> | Would it help if we allowed private #x; class { private #x }, so you can preemptively declare that I don't want to share the outer? |
| 04:52 | <ljharb> | no |
| 04:52 | <bakkot> | I have argued that the specific change I want to make is likely to be web compat |
| 04:53 | <ljharb> | "existing code" requires not editing it |
| 04:53 | <bakkot> | I think the specific change you want to make is much less likely to be web compat |
| 04:53 | <ljharb> | using private means it's not pre-existing code anymore |
| 04:53 | <bakkot> | I am not at all talking about examples with private and am very confused why you think I am |
| 04:53 | <ljharb> | i'm not suggesting changing things in the absence of private? |
| 04:53 | <ljharb> | i'm saying only when private exists this change should happen |
| 04:53 | <ljharb> | thus, impossible to be web incompatible. |
| 04:54 | <ljharb> | it would continue working the same if you don't use a private declaration |
| 04:54 | <bakkot> | right, ok, so your proposal is to have two different kinds of private fields |
| 04:54 | <ljharb> | (and if you use one, the semantics are ALREADY changing, so this is just another change) |
| 04:54 | <bakkot> | I do not want to have that |
| 04:54 | <ljharb> | no |
| 04:54 | <ljharb> | the field is the same |
| 04:54 | <Justin Ridgewell> | I think the biggest mistake that we made recently was allowing class { #x } instead of class { private #x } |
| 04:54 | <ljharb> | the syntactic line in the class body that you are already changing the semantics of would have an additional semantic change. neither change alters how private fields work (it's not a private field til it's installed) |
| 04:54 | <Olivier Flückiger> | that would be extremely confusing if private property declarations would be context dependent |
| 04:55 | <ljharb> | they already are! |
| 04:55 | <ljharb> | the presence of private #x changes how things work |
| 04:55 | <Olivier Flückiger> | no, they are not |
| 04:55 | <ljharb> | if it didn't then the proposal wouldn't do anything |
| 04:55 | <Olivier Flückiger> | the private changes the place of declaration. |
| 04:56 | <Olivier Flückiger> | it does not change what #x =1 means |
| 04:56 | <ljharb> | class { #x = 1 } class { #x = 1 } has two distinct private fields. private #x; class { #x = 1 } class { #x = 1 } has one. that is a semantic change based on the presence of the declaration |
| 04:56 | <ljharb> | it does |
| 04:56 | <ljharb> | because in the first, it means "make a new distinct field" and in the second it means "reuse the existing one" |
| 04:56 | <ljharb> | that is a change of what it means |
| 04:57 | <ljharb> | (concretely there is almost certainly a normative spec delta in the part of the spec that installs private fields as a result of the proposal because the semantics change) |
| 04:58 | <Olivier Flückiger> |
|
| 04:58 | <ljharb> | yes that is a semantics change |
| 04:58 | <ljharb> | because it makes a change to that 3-item list |
| 04:58 | <ljharb> | i'm really confused how this is confusing |
| 04:59 | <ljharb> | that list is the semantics. that list changes. ∴ it is a semantics change |
| 04:59 | <bakkot> | ljharb:
|
| 04:59 | <bakkot> | is your proposal:
|
| 04:59 | <bakkot> | for the first, I think there is a web compat risk |
| 04:59 | <ljharb> | the latter |
| 04:59 | <ljharb> | the former would indeed be a web compat risk which is why i never suggested it |
| 05:00 | <bakkot> | for the second, I think it would be very bad if that error was dependent on whether the field was declared with private #x or not |
| 05:00 | <Olivier Flückiger> | one is changing the scoping rules in the parser. the other is changing runtime behavior based on context. I would really not want the latter |
| 05:00 | <ljharb> | why? |
| 05:00 | <bakkot> | because I do not think it makes sense for that error to depend on how the name was declared |
| 05:00 | <ljharb> | ok but those are still both "semantics" |
| 05:00 | <ljharb> | why? changing between var/let/const - ie, how vars are declared - makes context-dependent errors |
| 05:00 | <Justin Ridgewell> | This feels very much like the protected override bug we had in Backbone |
| 05:01 | <bakkot> | those are different kinds of variables |
| 05:01 | <bakkot> | and I do not want there to be different kinds of private fields |
| 05:01 | <Justin Ridgewell> | If you try to override the same field in a subclass, it's not going to be the one that's present during the parent's constructor execution. |
| 05:01 | <Justin Ridgewell> | I think it's an error to try and override the field in the subclass at all. |
| 05:02 | <bakkot> | yes |
| 05:02 | <ljharb> | hm |
| 05:03 | <Justin Ridgewell> | Given that, I really want Olivier's example to throw an error. It should error very loudly that the type of code you're attempting to write has a bug. |
| 05:04 | <ljharb> | is [#x] = 1 code this proposal would let you write? |
| 05:04 | <bakkot> | nope |
| 05:04 | <ljharb> | i think i saw that on the queue |
| 05:04 | <bakkot> | (it was last time I presented it but that confused everyone a lot) |
| 05:04 | <bakkot> | that was a suggestion |
| 05:04 | <bakkot> | from danielrosenwasser I think |
| 05:04 | <ljharb> | ok so you’d be forced to make one of the classes - but not the other - imperative? |
| 05:05 | <bakkot> | yes, the one where you are only assigning to an existing field, rather than declaring it, would have to use the syntax that is only assignment, not declaring it |
| 05:05 | <bakkot> | seems good to me |
| 05:05 | <ljharb> | ok, I’m convinced. Thank you (i stand by all my clarifications tho) |
| 05:06 | <Olivier Flückiger> | Unpopular opinion: we have too small timeboxes! If we spend all the next topics time to talk here that is kinda bad for the conversation |
| 05:06 | <bakkot> | I was considering making this one larger but I did already have > 3 hours on the agenda... |
| 05:06 | <Mathieu Hofman> | I never said anything about async code. My concern is about avoiding introducing new synchronous re-entrancy. If you have synchronous code doing cancellation, the receiving system handling the cancellation is not currently at the top of the stack (the triggering system of the abort is). What the callback does is ultimately modify some state in the system handling the abort. If that system is somewhere already on the call stack it needs to be capable of handling that state change when the stack unrolls to it, so checking for an abort state is already a requirement. Same story about entrypoints to the system, which must already check for aborted state. The only difference is how much "cleanup" you'd be able to do immediately vs when when the system checks for an aborted state. Concretely in your example, the queue loop can check the abort state of the signal associated with the task before executing it. I don't see how that requires any modification of the tasks themselves, or why that would be much less efficient than immediately removing the task from the queue. |
| 05:06 | <ljharb> | nobody will mind a Kevin day |
| 05:06 | <Michael Ficarra> | the process document is like that for a reason! |
| 05:06 | <Michael Ficarra> | no time to explain because note taking |
| 05:06 | <Justin Ridgewell> | Under Jordan's suggestion:
But if we kept the "can't install twice", this throws. I like the throwing. |
| 05:07 | <bakkot> | Michael Ficarra I can take over for notes for a minute |
| 05:07 | <rkirsling> | on the present topic, I think Symbol.for is a terrible name and shouldn't be mimicked |
| 05:09 | <rkirsling> | (but I really like the proposal and want it to advance) |
| 05:10 | <Chris de Almeida> | yes.. I always feel bad for presenters who have to follow a hotly debated topic that spills over into the chat for an extended period |
| 05:11 | <Chris de Almeida> | I'm not sure how to solve for this though... |
| 05:11 | <Michael Ficarra> | @Chris de Almeida @Ashley Claymore So on the Stage 2 wording, we intentionally want to add emphasis to the non-final nature of the proposal at that stage because the primary purpose of that explanation is for communicating to the community. We had a lot of issues in the past with earlier wording that made things sound too much like a commitment. The community had a lot of trouble with misunderstandings of our proces in the past. |
| 05:11 | <Michael Ficarra> | thanks @bakkot I will take back notes |
| 05:12 | <Olivier Flückiger> | maybe let attendees up/down vote timeboxes upfront :) |
| 05:12 | <Michael Ficarra> | no! |
| 05:13 | <bakkot> | in my example, the task queue does not need to have any awareness of signals at all, and there is no notion of signals being "associated with" a task |
| 05:14 | <Michael Ficarra> | it is rude to assume what somebody is going to say based on their queue topic and then pre-reply to a strawman |
| 05:14 | <ljharb> | why is that rude? |
| 05:14 | <ljharb> | it doesn't interfere with their ability to still speak their item |
| 05:15 | <Michael Ficarra> | because you're making a strawman |
| 05:15 | <ljharb> | i suppose if you're stating your interpretation of their comment as if it's fact, that'd be rude. but that's not inherent in pre-replying |
| 05:17 | <Rob Palmer> | regardless of whether it's rude - speculative queue entries risk being distracting by unnecessarily widening the conversation |
| 05:17 | <ljharb> | that's certainly true |
| 05:17 | <ljharb> | altho often the widening leads to useful discussion |
| 05:18 | <bakkot> | not sure if serious, but re keith's point: throw if the object's keys are not in alphabetical order? |
| 05:18 | <ljharb> | keith_miller: it's not just "insertion order" today tho; numeric keys get sorted already iirc? |
| 05:18 | <bakkot> | would make it more annoying to use, but like... works ok |
| 05:28 | <Olivier Flückiger> | I think there the order is actually implementation defined |
| 05:29 | <Justin Ridgewell> | ^ We strongly defined the ordering of numeric keys and string keys |
| 05:29 | <Justin Ridgewell> | I remember that proposal |
| 05:29 | <Olivier Flückiger> | hmm, last time I looked there was more wiggle room than I expected |
| 05:29 | <bakkot> | there's wiggle room if you change out the prototype while in the middle of a for-of or something |
| 05:29 | <bakkot> | and in a few similar cases |
| 05:30 | <Olivier Flückiger> | ah, yes! |
| 05:30 | <bakkot> | but in the case of an object that is not changing during enumeration, it's fully defined |
| 05:30 | <Olivier Flückiger> | deleting numeric keys while iterating |
| 05:30 | <Olivier Flückiger> | (was the thing I looked at) |
| 05:32 | <Michael Ficarra> | reminder: the ♻️ button in TCQ has pre-saved messages that you can use (and add your own) |
| 05:35 | <bakkot> | I guess not being able to write "r" "g" "b" "a" keys in that order is a moderately compelling reason not to go with my suggestion of throwing in on out-of-order keys |
| 05:42 | <ljharb> | @erights Mark Miller (Agoric) MM: why must a composite's realm not be observable? all other objects' realm is unavoidably observable |
| 05:43 | <Chip Morningstar> | If you require keys to be fed in in sorted order, then the first thing that will happen is somebody (probably several somebodies) will create an NPM package that wraps the Composite creator in something that makes a copy of the given object with its keys sorted. And then everybody will just use that, and complain about "why can't Composite just do this itself?" |
| 05:43 | <bakkot> | also true yes |
| 05:45 | <Olivier Flückiger> | Did I miss that part where we established the exact argument for why it has to be cross realm? |
| 05:46 | <Rob Palmer> | as an observation, this feels like the closest we've ever been to genuine consensus on composites / r&t. |
| 05:46 | <ljharb> | mark said something along the lines of "it's value-like, and values aren't tied to a realm" (i assume meaning primitives) |
| 05:46 | <ljharb> | but it has properties, and can contain an object, which in turn likely points to a realm, so i'm still unclear on the requirement |
| 05:48 | <ljharb> | also if you need to take a composite from one realm and use it in another and hide the original realm, you could Composite({ ...otherRealmComposite }) before handing it out i guess? |
| 05:48 | <Olivier Flückiger> | Right, but to mee this sounds more like a matter of taste. It might not be nicely uniform, but not strong enough if there are hard problems with the alternative. |
| 05:49 | <ljharb> | so far i agree with that take, but i'm hoping mark or his compatriots can clarify further |
| 05:49 | <Olivier Flückiger> | (and the hard problems are clearly there, requiring distributed GC...) |
| 05:49 | <Ashley Claymore> | alternative for (always) sorting is two phase api:
|
| 05:50 | <ljharb> | oof, unnamed args make that bad news bears imo |
| 05:55 | <Mathieu Hofman> | I'm a little tired and fuzzy on the specifics right now, so I'll try to clarify with Mark before replying. |
| 05:57 | <Ashley Claymore> | I can bring Composites to a ~~TG5~~ TG3 meeting too if that helps |
| 05:57 | <Chris de Almeida> | TG5? or TG3 ? or both? |
| 05:57 | <Ashley Claymore> | All the TGs |
| 05:57 | <Chris de Almeida> | nice |
| 05:57 | <Ashley Claymore> | but yes TG3 sorry |
| 05:58 | <Jesse (🇯🇵)> | I imagine that TG4 is neutral on composites |
| 06:00 | <Chris de Almeida> | ominous ☝️ |
| 06:02 | <James M Snell> | I'm wondering what message did such that it had to be removed |
| 06:03 | <Jesse (🇯🇵)> | I thought it was harmless |
| 06:06 | <nicolo-ribaudo> | A message that belonged to TDZ and not here :P |
| 06:19 | <Mathieu Hofman> | Ok so I clarified things with Mark. keith_miller and Ashley Claymore 's description of the mechanism as a registry tied to the Composite "constructor" convinced him that same-realm interning is fine. He's actually asking that the mechanism be specified like that if possible, with the registry tied to the "constructor". |
| 06:20 | <rkirsling> | ! |
| 06:21 | <Ashley Claymore> | thanks Mathieu Hofman ! |
| 06:23 | <Chris de Almeida> | soooooo.... continuation? |
| 06:25 | <James M Snell> | I'm just catching up so sorry for throwing this in so late.. but if we can get the error code property proposal advanced then we have options there also. But I think it's not unreasonable to consider adding AbortError as an additional native error type such that err.name === 'AbortError' checks continue working even if err instanceof DOMException might not. The one thing I don't think we can necessarily do, however, is require that abort() always take a reason. There's way too much code out there that just calls abort() relying on the default reason.... we might be forced to just say that the default reason is an implementation specific detail |
| 06:49 | <ljharb> | and yet, ES6 broke many such guarantees :-( |
| 07:03 | <Christian Ulbrich> | MM has a point, although personally I do not see so much use of the WeakX stuff. |
| 07:04 | <ljharb> | nope, usage of weak stuff is probably super tiny |
| 07:04 | <ljharb> | and i'd bet creation of a weakref in a loop that isn't preserved across loop iterations is an infinitesimal % of that |
| 07:05 | <Christian Ulbrich> | Still its guessing. bakkot had some numbers for his arguments, which makes deciding things easier... |
| 07:07 | <Christian Ulbrich> | bakkot: How did you do your measuring across the top 17k npm packages for the "private stuff"? |
| 07:08 | <Michael Ficarra> | (last-ditch effort): @waldemar can you check your DMs for a message from me? |
| 07:08 | <Mathieu Hofman> | Nicolo's audio is really bad for me, anyone else ? |
| 07:08 | <peetk> | sounds fine in the room |
| 07:08 | <Christian Ulbrich> | Mathieu Hofman: For us in the room it is good, albeit a bit creaky |
| 07:08 | <Michael Ficarra> | I think this is better than usual for NRO's audio |
| 07:17 | <keith_miller> | Mathieu Hofman: I also thought about it a bit more, I don't think the global registry is actually a blocking problem. The composite itself doesn't have to know about the realm it's from (we can reuse the same logic we use for wasm objects). That said, I would still mildly prefer a per-realm cache |
| 07:17 | <nicolo-ribaudo> | I'm on a mac with airpods, I don't think I can make it better by changing something in my setup |
| 07:18 | <ljharb> | i expect the risk to be small but i strongly disagree that most people avoid defaults |
| 07:18 | <ljharb> | the airbnb styleguide has always strongly recommended preferring them, as an example. |
| 07:18 | <ljharb> | (and they were all equally compatible iirc; the only argument i'm aware of is that IDEs automatic refactoring chooses not to support defaults as well as names) |
| 07:20 | <Christian Ulbrich> | I would regard all "people do this or that" as personal view, because w/o data, this is what it is. Defaults have certain usages and in React eco system they have been used extensively in the past... |
| 07:20 | <Mathieu Hofman> | It sounded to me like a combination of packet latency and slight clipping of the microphone |
| 07:21 | <Mathieu Hofman> | actually it sounds like the echo cancellation going crazy, possibly because there is echo in the room? |
| 07:29 | <ljharb> | absolutely. but it's totally possible to have a reasonable guestimation of usage even without data. i just have lots of anecdata that supports wide (but not majority, certainly) usage of defaults |
| 07:30 | <Justin Ridgewell> | There was an issue when trying to default export with named exports from libraries. We had to invent the es module wrapper pattern and get all bundlers to agree to it. |
| 07:30 | <ljharb> | ahh k |
| 07:30 | <ljharb> | i think by the time ESM usage become truly widespread that was already in the past tho |
| 07:31 | <Justin Ridgewell> | Yah |
| 07:31 | <ljharb> | (both were way before 2015, either way) |
| 07:31 | <ljharb> | (also, thanks for helping with that work; the wrapper pattern is far superior to the other coping mechanisms people were using) |
| 07:32 | <Christian Ulbrich> | ljharb: I distinctly meant the "all" part, personal input or input from a developer's (mine) or a library author (yours) perspective is always good. |
| 07:34 | <hax (HE Shi-Jun)> | I still worry about export * from xxx. It was said the refacotor harzard issue is same as other named export. But I think it's not. I believe the original design is based on the assumption that default is special. It's obvious that the conflict possibility is very different between default and normal names. |
| 07:35 | <peetk> | but in the case of conflicts the key gets dropped? |
| 07:37 | <ljharb> | the refactoring hazard only applies to dynamic import, not static |
| 07:37 | <ljharb> | iow there'd have to be code doing import() that relied on the absence of .default or switched on its presence |
| 07:37 | <ljharb> | (altho changing the syntax might require import statement linters to make changes, like eslint-plugin-import) |
| 07:39 | <hax (HE Shi-Jun)> | I believe refactor hazard mentiond by AWB, Yahuda and Dave Herman was not dynamic but static import, because there was no dynamic import in that day. |
| 07:39 | <Ashley Claymore> | the refactoring hazard is immediately mitigated by having a single test for the default export. |
| 07:39 | <Ashley Claymore> | It's not a subtle issue |
| 07:40 | <ljharb> | current code that tries to import the default from a re-exporting module will have an early error, and with the proposal won't |
| 07:40 | <ljharb> | so i'm not sure what the hazard would be |
| 07:40 | <Ashley Claymore> | right |
| 07:40 | <Ashley Claymore> | it's only a 'hazard' for a code change that is shipped to production without being run once |
| 07:40 | <hax (HE Shi-Jun)> | That's what I worry. Because we not fully understand the hazard they mentioned. |
| 07:40 | <Ashley Claymore> | I think we do fully understand it |
| 07:41 | <ljharb> | we might not understand what they meant - but i think we fully understand that there is no hazard. so either there's confusion or they were just wrong |
| 07:41 | <Justin Ridgewell> | Chris de Almeida: What were the security benefits? Did I miss that in the slides? |
| 07:41 | <ljharb> | (or they were talking about people migrating code from CJS/AMD/etc to ESM, and we're talking about ESM to ESM here) |
| 07:43 | <hax (HE Shi-Jun)> | Even it's what u understand, I don't agree default is same as named export. It has very higher conflict possibility than named exports. |
| 07:44 | <Chris de Almeida> | The People yearn for Composites |
| 07:45 | <nicolo-ribaudo> | I was not expecting support based on security since it's never being a selling point of the proposal, but if I had to guess is because you can statically tell whether your bundler will bundle something or not, thus avoid accidentally sending code to the front end that's not meant to be sent there? |
| 07:47 | <Chris de Almeida> | you are potentially reducing what is loaded and executed |
| 07:47 | <Chris de Almeida> | so decreased surface area |
| 07:48 | <Chris de Almeida> | and supply chain risk |
| 07:48 | <ljharb> | you'd just wrap it, no Mathieu Hofman ? |
| 07:51 | <Michael Ficarra> | parameter ordering before stage 2?! |
| 07:55 | <nicolo-ribaudo> | About the
with this proposal If It is true that adding a |
| 07:57 | <ljharb> | frodo_secrets.png |
| 07:58 | <Ashley Claymore> | and tools can statically see if you have two export * with only one default and suggest making it explicit. CI can catch this. |
| 08:00 | <Ashley Claymore> | And right now they have to do an explicit default export from the barrel file - so they should continue to do so |
| 08:01 | <ljharb> | more importantly they can continue to do so, and it'll just be redundant or back-compat-ful |
| 08:03 | <Ashley Claymore> | yeah, continuing to do so fully avoids the refactoring hazard |
| 08:03 | <Ashley Claymore> | explicit export always wins |
| 09:01 | <rkirsling> | Keith made a really good point that the way we're using RangeError would've in hindsight been better called ValueError |
| 09:18 | <Michael Ficarra> | Keith made a really good point that the way we're using RangeError would've in hindsight been better called ValueError |
| 09:27 | <rkirsling> | 'cause one can hung up on what counts as a "range" but it's really a matter of the value not adhering to expectations |
| 09:31 | <ljharb> | exactly that. it’s not about “what a range is”, it’s about “it’s the right type but still an unacceptable value” |
| 14:54 | <bakkot> | ran a script that downloaded and parsed all of them. this works well for some things and not others. It would be easy to check for the literal string "new WeakRef" without even parsing, for example, and with some parsing I could check if that happens syntactically in a loop, but figuring out if the call happens in a function transitively called from within a loop would be much harder (well, impossible in principle but if you were willing to spend enough effort you could get most cases) |
| 17:51 | <bakkot> | Olivier Flückiger: on the topic of sorting keys for composites, my expectation is that it will be pretty unusual to create a composite with more than four or five keys. are you still worried about having to deal with sorting in that case, or is it only about larger objects? |
| 17:58 | <iain> | FWIW, SM has a rough sketch of optimizing composite key sorting that we're happy enough with. (If you cache a shape/permutation pair, then you can pre-compute the permutation from unsorted to sorted keys once and reuse it on subsequent calls.) |