00:47 | <littledan> | I am having more trouble than I expected being awake for TC39, so I will skip the first half of the day, and be present in the second half. Thanks for understanding. |
00:59 | <bakkot> | ljharb: my computer started freezing as soon as you started addressing me so I have absolutely no idea what you said |
01:00 | <ljharb> | bakkot: ah np, was just casually mentioning that https://github.com/tc39/ecma262/pull/2125 is ready to go once you and/or shu have signed off on it :-) |
01:00 | <bakkot> | gotcha, thanks |
01:02 | <ljharb> | my presentation: https://github.com/tc39/proposal-private-fields-in-in/issues/7 |
01:02 | <devsnek> | imagine, __proto__ outside of annex b |
01:02 | <shu> | haha dang, jmdyck said he wants to stop thinking about this |
01:02 | <shu> | he is usually indefatigable |
01:12 | <bakkot> | for the notes, who is speaking? |
01:12 | <ryzokuken> | Dan Clark? |
01:12 | <Michael Ficarra> | bakkot: DDC |
01:13 | <leobalter> | ryzokuken: I just want to confirm - and inform - the Realms champions will be available tomorrow for the overflow time, but some people won't be available tonight |
01:14 | <Aki> | oh that's helpful info |
01:14 | <Aki> | leobalter: i was just about to attempt to squeeze it in later today |
01:15 | <leobalter> | Thanks, Aki ! By the end of the meeting yesterday we said Wednesday and Caridy won't be able to attend today/tonight |
01:15 | <ryzokuken> | leobalter: thanks for letting us know! |
01:15 | <leobalter> | and by Wednesday we mean the 3rd day of the meetings |
01:15 | <Aki> | w/th |
01:16 | <Aki> | leobalter: after lunch, right? |
01:17 | <leobalter> | Let me confirm with Caridy, because I'm guessing the first time available would be doable |
01:17 | <Aki> | okay. i just had y'all's scheduling constraints |
01:19 | <leobalter> | Aki: Caridy is available after 11PM East Time (3rd day)... this should be the lunch time |
01:31 | <Tierney Cyren> | FWIW I agree with @shu |
01:31 | <Tierney Cyren> | damn it |
01:31 | <Tierney Cyren> | I'm still not used to the autocomplete |
01:32 | <devsnek> | what is the host hook on this slide for? |
01:32 | <Tierney Cyren> | I think allowing some JavaScript assertion is important |
01:33 | <Tierney Cyren> | I got this book at a thrift store when I was a kid |
01:33 | <Tierney Cyren> | this was in like 2009 or something |
01:33 | <Tierney Cyren> | JScript always stuck in my head after that |
01:34 | <devsnek> | ohno |
01:36 | <devsnek> | decorators? in my javascript? |
01:37 | <ljharb> | 💩 queue advance? |
01:38 | <bterlson> | queue advanced, thanks and sorry |
01:53 | <HE Shi-Jun> | the example code is leaking privates... |
01:53 | <ljharb> | intentionally, sure |
01:54 | <HE Shi-Jun> | no, i mean it's only want to leak to test, but actually someone can get it |
01:55 | <devsnek> | i think he means, now everything that is not the test can use it too |
01:55 | <devsnek> | but that's because they stored it on metadata |
01:55 | <ljharb> | true, because symbols are public |
01:55 | <devsnek> | if you stored it somewhere else, like in the test library, it wouldn't be leaked |
01:55 | <HE Shi-Jun> | So it's a bat example... |
01:55 | <HE Shi-Jun> | bad example |
01:55 | <devsnek> | 🤷♀️ |
01:59 | <HE Shi-Jun> | devsnek: So we should fix the example to store it in somewhere else, or people may just copy the example code in the proposal repo :) |
02:02 | <HE Shi-Jun> | I remember rbuckton have a similar proposal (but different syntax) for auto accessor? |
02:04 | <leobalter> | We are a bit faster compared to the initial schedule, I believe it's good if we want to extend time to clear out questions about Decorators |
02:04 | <leobalter> | as in, saving from time when it's eventually presented for Stage 3 |
02:05 | <bakkot> | ljharb: you can just have a different private field that you check, surely? |
02:05 | <ljharb> | objects can be partially populated with fields. |
02:06 | <bakkot> | meh |
02:06 | <bakkot> | technically true, not super relevant |
02:06 | <devsnek> | lol |
02:06 | <bakkot> | just put the field next to the accessor, now both must exist or neither do |
02:06 | <ljharb> | there's also value in being able to be explicit instead of dancing around what i'm trying to check |
02:06 | <bakkot> | sorry, for the notes, who just talked? |
02:06 | <HE Shi-Jun> | bakkot: seems not a good code style :) |
02:07 | <bakkot> | eh, checking in general seems like not good code style |
02:07 | <Tierney Cyren> | sounds like a good ESLint contribution :P |
02:07 | <bakkot> | just do the thing and if people misuse your class they get an error, it's fine |
02:07 | <bakkot> | static methods should check |
02:07 | <bakkot> | but not this |
02:07 | <ljharb> | lol that is a subjective debate that probably isn't productive to have, but suffice to say that is not a universal api design principle in userland |
02:07 | <HE Shi-Jun> | so if auto accessor i think we should use class brand check (class.hasInstance proposal) |
02:08 | <bakkot> | for the notes, who just talked? |
02:08 | <bakkot> | ah, rgn, thanks whoever put that in |
02:08 | <Josh Blaney> | richard gibson, I was looking |
02:11 | <devsnek> | -2 points for not using .js.org |
02:12 | <Tierney Cyren> | it would be nice if that was in a more neutral home |
02:12 | <Tierney Cyren> | (js.org) |
02:14 | <Richard Gibson> | shu: when you take the questions back, please make sure to ask about interleaved vs. at-the-end initializers |
02:15 | <shu> | Richard Gibson: specifically, if we would have concerns with making addInitializer unconditionally available if they were all at the end? |
02:15 | <Richard Gibson> | correct |
02:15 | <shu> | roger |
02:15 | <shu> | that feels okay to me |
02:16 | <Richard Gibson> | it may not fly for other reasons, but I am still interested in the answer |
02:16 | <shu> | i can't speak to if the use cases @init is supposed to solve still work fine with all-at-the-end |
02:16 | <shu> | but impl wise seems fine |
02:16 | <Richard Gibson> | right, exactly |
02:16 | <ljharb> | my @bound use cases do require it be interleaved |
02:16 | <devsnek> | initializers at the end feels weird in the case of multiple decorators |
02:17 | <ljharb> | so that number 2 can store a bound reference to number 1, eg |
02:18 | <bakkot> | Justin Ridgewell: this actually identical to the find/findLast precedent |
02:21 | <Richard Gibson> | @ljharb: how would that break down with at-the-end evaluation? |
02:21 | <ryzokuken> | bterlson: Aki could you give the delegate role to dcrousso ? |
02:22 | <Richard Gibson> | or rather, at-the-beginning so it can be accessed in the constructor |
02:24 | <devsnek> | someone needs to be muted |
02:24 | <ljharb> | Richard Gibson: class C { @init:bound x() {} foo = this.x; } - now, on a const i = new C() , i.foo is an unbound x if not interleaved |
02:25 | <Richard Gibson> | ack, thanks |
02:25 | <leobalter> | "any objections?" almost silence but background noise that sounds like hammering |
02:25 | <ljharb> | ok to interrupt and ask if the mic gain can be turned down? |
02:25 | <Michael Ficarra> | ow my ears |
02:25 | <devsnek> | is philip making popcorn |
02:26 | <Michael Ficarra> | so much better, thanks |
02:26 | <devsnek> | setTimeout with a capital T |
02:27 | <devsnek> | oh just namespaces |
02:28 | <devsnek> | for anyone else who is curious https://gc.gy/93934712.png |
02:33 | <Jamie Kyle> | Sorry if I misunderstood, ljharb you were saying capital implied constructor? What about Math/Reflect/etc? |
02:33 | <ljharb> | Jamie Kyle: a nested one implies constructor to me. Math.Foo would imply the same to me. top-level is fine as a "namespace or constructor" |
02:33 | <ptomato> | leobalter: https://github.com/tc39/proposal-temporal/issues/1583 is the context |
02:34 | <leobalter> | Thank you! |
02:34 | <devsnek> | shu coming in with the good logic |
02:34 | <devsnek> | i can't argue with that |
02:34 | <devsnek> | although i prefer the aesthetics of lowercase |
02:35 | <Jamie Kyle> | I agree that Temporal.now feels like a method to me, especially with Date.now() |
02:37 | <HE Shi-Jun> | If Temporal.Now , I think many would use new Temporal.Now() , is that allowed? |
02:37 | <ljharb> | that's my confusion argument; and no, that would throw too |
02:37 | <ljharb> | since this is just a normal object. |
02:37 | <HE Shi-Jun> | so I will like to support Temporal.now() :) |
02:38 | <devsnek> | i don't think people will do that |
02:39 | <HE Shi-Jun> | devsnek: Not sure, could we have research on such things? |
02:39 | <Jamie Kyle> | The only things I've seen in the JS community with regards to nested namespaces is capitalizing them. Such as in https://www.typescriptlang.org/docs/handbook/namespaces.html
|
02:40 | <ljharb> | i don't think people will do either Temporal.now() or new Temporal.Now() - and if they do, they'd only do it once. so i don't think that's an important point either way. |
02:40 | <bakkot> | e.g.
or whatever |
02:40 | <Jack Works> | anyway typescript will stop me when I call API in a wrong way, but yes Temporal.now looks like Date.now |
02:40 | <ljharb> |
|
02:41 | <devsnek> | i think we should just ask if anyone would block the current naming since its current |
02:41 | <Jamie Kyle> | Its just a clear place where I can see people naming things explicitly like this |
02:41 | <Jamie Kyle> | There are lots of other examples. i.e. React.PropTypes |
02:41 | <ljharb> | i've seen and written plenty of code naming these things with lowercase on nested things also. |
02:42 | <ljharb> | and a react component has .propTypes ; react itself isn't even consistent there. |
02:42 | <Jamie Kyle> | Not a namespace! |
02:43 | <HE Shi-Jun> | To me, Temporal.now is more like globalThis.parseInt , not React.PropTypes :) |
02:44 | <Jamie Kyle> | parseInt is a function though? |
02:44 | <bakkot> | To me, Temporal.now is more like globalThis.parseInt , not React.PropTypes :) |
02:46 | <bakkot> | syg: can you fix up the last thing you said in the notes, bot mangled it and I missed it |
02:46 | <HE Shi-Jun> | oh! I made mistake! So i slightly support Temporal.Now now :) |
02:47 | <devsnek> | i'm very sad about this topic, now i'll never be able to propose array.forEach((v) => { if (c(v)) Array.forEach.break() }) |
02:48 | <Jamie Kyle> | twitter poll https://twitter.com/buildsghost/status/1415140845058023429 |
02:48 | <Michael Ficarra> | which is more effective at dooming your agenda item? "this is universal truth and should be completely uncontroversial" or "this should be quick"? |
02:48 | <HE Shi-Jun> | Array.forEach.break() sounds interesting 😀 |
02:49 | <devsnek> | yeah strong block on both points |
02:49 | <devsnek> | :^) |
02:50 | <Jack Works> | does Intl have nested namespace |
02:50 | <devsnek> | no |
02:50 | <Jack Works> | iirc Intl has lots of uppercase in their API |
02:50 | <Jamie Kyle> | they are all constructors |
02:50 | <devsnek> | intl has only one level before a function |
02:50 | <legendecas> | what if array.forEach((v) => { if (c(v)) SomeFunctionThatWillCallArrayForEachBreak() }) ? |
02:50 | <devsnek> | they're either Intl.Constructor or Intl.callable |
02:51 | <ljharb> | tbh "nested namespace" is so rare a thing that i very much doubt this precedent will be needed in the future (altho setting one either way is obv good) |
02:51 | <HE Shi-Jun> | legendecas: I guess break? though it seems very magical |
02:52 | <devsnek> | "until someone proposes call/cc" |
02:52 | <devsnek> | is this a challenge |
02:52 | <Michael Ficarra> | legendecas: that's not a break completion though |
02:55 | <ljharb> | iain: re Math, i do not believe so |
02:56 | <ljharb> | iirc Compartments has a very very short list of things to virtualize per compartment, and i suspect Temporal.now, Date, and Function are the main ones |
02:56 | <legendecas> | legendecas: that's not a break completion though |
02:56 | <iain> | Sorry, maybe Date is a better example there |
02:56 | <ljharb> | that's a constructor tho |
02:57 | <Michael Ficarra> | legendecas: nope, you can implement that with normal completions |
02:57 | <iain> | Ah, good point |
03:03 | <shu> | for these aesthetic guidance things where people's intuition differ |
03:03 | <shu> | i'd like to see the temperature check |
03:03 | <devsnek> | ye |
03:03 | <ptomato> | agreed! the best temperature check I had previously, was the thread that I linked above, which is not a large sample size |
03:06 | <bakkot> | oh yeah I forgot we had that feature! |
03:06 | <bakkot> | this seems like a good use case for temperature check |
03:15 | <ptomato> | one meeting with tcq-in-spreadsheet and we're back in the dark ages 😂 |
03:18 | <Jamie Kyle> | Just to share some results from searching in the community. Looking through all of the library/framework APIs which are documented by TypeScript in the DefinitelyTyped repository. You can find lots of examples of nested namespaces using both lowercase/capitalized naming: https://sourcegraph.com/search?q=context:global+repo:DefinitelyTyped/DefinitelyTyped+namespace+%5Ba-zA-Z0-9%5D%2B%5C.%5Ba-zA-Z0-9%5D%2B.*%5C%7B%24&patternType=regexp |
03:19 | <devsnek> | whoa |
03:19 | <devsnek> | code search |
03:19 | <ryzokuken> | the evidence says that the evidence is inconclusive |
03:19 | <devsnek> | what does copilot say i wonder |
03:20 | <Jamie Kyle> | I would say that the community not having consensus just means that it definitely should not block Temporal moving forward with .now |
03:20 | <bakkot> | I like shu's argument about, it probably shouldn't matter whether it's nested or not |
03:20 | <bakkot> | so if we'd capitalize it if it was globalThis.Now , we should capitalize it when it's globalThis.Temporal.Now |
03:20 | <devsnek> | https://gc.gy/93937845.png |
03:21 | <ryzokuken> | that's cheating |
03:21 | <ryzokuken> | they probably trained it on our code too |
03:21 | <devsnek> | if they had, it would not be function() { |
03:21 | <Jamie Kyle> | They are just on an outdated proposal |
03:21 | <devsnek> | lol |
03:21 | <ryzokuken> | lol exactly my point |
03:21 | <ryzokuken> | I wrote the old version |
03:22 | <ryzokuken> | now and parse were top level functions on Temporal |
03:22 | <bakkot> | Just to share some results from searching in the community. Looking through all of the library/framework APIs which are documented by TypeScript in the DefinitelyTyped repository. You can find lots of examples of nested namespaces using both lowercase/capitalized naming: https://sourcegraph.com/search?q=context:global+repo:DefinitelyTyped/DefinitelyTyped+namespace+%5Ba-zA-Z0-9%5D%2B%5C.%5Ba-zA-Z0-9%5D%2B.*%5C%7B%24&patternType=regexp |
03:22 | <bakkot> | (and conversely) |
03:23 | <devsnek> | https://gc.gy/93937990.png |
03:23 | <bakkot> | I did say "almost" |
03:23 | <devsnek> | lol i like this one https://gc.gy/93938007.png |
03:25 | <Jamie Kyle> | 155 results for Capital.lowercase |
03:26 | <devsnek> | how many of them start with a character with no case mapping |
03:26 | <Jamie Kyle> | uhh, whats that regex |
03:27 | <devsnek> | [^\p{Upper}\p{Lower}] i think? |
03:27 | <Jamie Kyle> | :( |
03:27 | <devsnek> | lol |
03:28 | <ptomato> | I think I change my preference to Temporal.𝒩ow |
03:28 | <ryzokuken> | btw, as I mentioned before, I think Now is a better choice in this specific case because of the precedent set by Date.now and everything else in this space |
03:28 | <Jamie Kyle> | Temporal.Ñow |
03:28 | <Hemanth H.M> | .now or Never |
03:29 | <Jamie Kyle> | Temporal.LikeWhatEvenIsNowWhenYouThinkAboutIt |
03:29 | <devsnek> | Temporal.Never |
03:29 | <bakkot> | 500+ results for Upper.Upper , 142 for Upper.lower |
03:30 | <Jamie Kyle> | 500+ results for Upper.Upper ? |
03:30 | <Hemanth H.M> | Jamie Kyle deep philosophy! Reminded me of George Carlin 😅 |
03:30 | <bakkot> | Do you have case-sensitive enabled, I'm getting 194 for |
03:30 | <devsnek> | :O |
03:30 | <ryzokuken> | Temporal.Current |
03:31 | <devsnek> | Temporal.🆕 |
03:31 | <ptomato> | ok, that's the best one |
03:31 | <devsnek> | whoa i've never seen something render an emoji inverted before |
03:31 | <ptomato> | I change my preference to that |
03:31 | <ryzokuken> | unicode moment |
03:31 | <ryzokuken> | oh wait this is #delegates |
03:31 | <ryzokuken> | let's go to #tdz? |
03:34 | <Jamie Kyle> | Aside: I found sourcegraph really useful to find people who were doing stuff with my Object.hasOwn proposal, I'd highly recommend it when looking for community members doing stuff https://sourcegraph.com/search?q=context:global+Object%5C.hasOwn%5B%5EP%5D&patternType=regexp&case=yes |
03:41 | <ljharb> | tbh i'd be interested to see non-typescript results, since TS will be overly skewed by java/C# idioms |
03:43 | <Jamie Kyle> | I mean this repo is entirely dedicated to documenting APIs that are not written in TS |
03:44 | <ljharb> | lots of the types get names that never exist in the original JS |
03:46 | <Jamie Kyle> | If you click through the results, you can see most of them are documenting runtime constants/functions/classes that exist |
03:46 | <Jamie Kyle> | I'm not saying its perfect, but its a pretty good signal |
03:47 | <ljharb> | sure, but that's why i'd want to see the pure JS results - they'd contain all those without the skewed results from the TS-only names. |
03:47 | <devsnek> | can't you put lang:javascript |
03:48 | <Jamie Kyle> | Yeah but namespace doesn't exist so what would you search for |
03:49 | <Jamie Kyle> | I think the only conclusion thats ever going to be drawn here though is that the community has not clearly established a pattern one way or the other |
03:49 | <Jamie Kyle> | I think its a plus one to "not blocking on this" |
03:50 | <ljharb> | which imo kind of precludes using other langs/userland as an argument; also "confusion" since it can cut either way - so we're probably left with aesthetics, which is shaky ground to make precedent, or block a proposal, on |
03:51 | <Jamie Kyle> | lol but what will twitter think if JS isn't AESTHETIC? |
03:51 | <ljharb> | it'll always be aesthetic if you ask the right subset of people :-p |
03:53 | <ryzokuken> | we don't need to please everyone, just people who strongly believe in the JS aesthetic 😀 |
03:54 | <Jamie Kyle> | tell that to all the people who yelled at me for writing a blog post explaining the #privateMember syntax! |
03:54 | <ptomato> | just to reiterate, no proposal is being blocked on this |
03:54 | <ryzokuken> | the internet is... the internet |
03:55 | <devsnek> | i still don't like private fields |
03:55 | <devsnek> | and it's all your fault jamie |
03:56 | <Jamie Kyle> | :O |
03:56 | <devsnek> | (/s) |
03:56 | <bakkot> | private fields are extremely #aesthetic |
03:56 | <devsnek> | i do wish we did the symbol thing though |
03:57 | <bakkot> | I'm gonna not touch that |
03:57 | <devsnek> | lol |
03:57 | <ljharb> | because it's not reachable, or because you aren't going to reify your response |
03:58 | <Jamie Kyle> | booo |
04:06 | <Jamie Kyle> | I like "Concept Proposal" its very clear to me |
04:07 | <HE Shi-Jun> | Is strawperson stage 0 or stage 1? |
04:07 | <ryzokuken> | stage 0 |
04:08 | <devsnek> | "proposal" is stage 1 |
04:08 | <ryzokuken> | idea, proposal, draft and well... stage 4 |
04:08 | <ljharb> | what about "prototype", that's not overloaded at all |
04:08 | <littledan> | well, I guess I shared ljharb 's impression that, sure, you can refer to stages by these names, but they don't really have official names. Anyway, we throw around the term "strawperson" a lot and I like the idea of replacing it by "concept" |
04:09 | <devsnek> | the names are from https://tc39.es/process-document/ |
04:09 | <HE Shi-Jun> | maybe just "idea"? |
04:09 | <ryzokuken> | prototype sounds like later stage to me |
04:09 | <ptomato> | "stub" as suggested in one of the screenshotted tweets might meet this concern from Chip? |
04:09 | <ryzokuken> | yeah, I like "idea" |
04:09 | <littledan> | the names are from https://tc39.es/process-document/ |
04:09 | <littledan> | (never mind) |
04:10 | <devsnek> | yeah i don't think anyone really does |
04:10 | <devsnek> | we could just remove them |
04:10 | <devsnek> | yep lol |
04:10 | <HE Shi-Jun> | Agree to remove it. |
04:10 | <Jamie Kyle> | Stage 0-4 seem decently well taught in the community already |
04:10 | <HE Shi-Jun> | Actually chinese TC39 guys rarely use "strawperson" , we just use "stage X". |
04:10 | <ryzokuken> | I like the words, they are more understandable to people who aren't as active in the space |
04:11 | <littledan> | I think we can just rapidly agree that renaming this term (which we do use a lot) to "concept" is good |
04:11 | <ryzokuken> | Stage 3 means nothing to a regular JS developer |
04:11 | <devsnek> | find me a person who uses "proposal" to refer to only stage 1 |
04:11 | <ljharb> | yes but i don't think that's nearly as true as it was a few years ago. but also the stage names mean little to them as well |
04:12 | <Aki> | https://tc39.es/process-document/ |
04:13 | <littledan> | Hmm, I do think we should adopt "concept" informally, even if we take out this column |
04:13 | <ljharb> | do we even use the term "strawperson" informally tho? |
04:13 | <ptomato> | I have heard others use it in plenary, yes |
04:14 | <littledan> | well, I try to avoid it, since it's obscure, but in general yeah, it's a piece of jargon we throw around all the time |
04:14 | <ptomato> | https://github.com/tc39/notes/search?q=strawperson |
04:14 | <devsnek> | shane going for the nuclear option 👀 |
04:14 | <ptomato> | apparently not very often! |
04:15 | <Jamie Kyle> | "Stage 0-4" are used all over the place in tools |
04:15 | <littledan> | counterpoint: https://github.com/tc39/notes/search?q=strawman |
04:15 | <Hemanth H.M> | https://tc39.es/process-document/ |
04:18 | <Aki> | after shane we're at time |
04:20 | <HE Shi-Jun> | number is much general than word. It's very hard for us to know what "proposal"/"draft" stage is much bigger :) personally i use the chinese translation of "proposal"/"draft" for any stage < 4 ... :P |
04:21 | <Jamie Kyle> | Referring to stage 0 stuff as "proposal" is already the norm in the community https://twitter.com/search?q=tc39%20stage%200%20proposal&src=typed_query |
04:21 | <Jamie Kyle> | I see a few of yalls names in there 🤐 |
04:21 | <Hemanth H.M> | Stage-0 can be Proposal? |
04:21 | <ljharb> | they're all proposals tho |
04:21 | <ljharb> | change the number in that search and there'll be results for all of them, i'd suspect |
04:22 | <Aki> | Referring to stage 0 stuff as "proposal" is already the norm in the community https://twitter.com/search?q=tc39%20stage%200%20proposal&src=typed_query |
04:22 | <Jamie Kyle> | what is a temp check? |
04:23 | <HE Shi-Jun> | what the icon means? |
04:23 | <devsnek> | what is a temp check? |
04:23 | <HE Shi-Jun> | I support remove names at all, not sure which emojo i should choose |
04:23 | <ptomato> | there are descriptions above each emoji button? |
04:24 | <ljharb> | btw i refreshed tcq and my temp check vanished (cc @bterlson) |
04:24 | <Jamie Kyle> | ljharb: just to note, I can see yours |
04:24 | <waldemar> | Can we please get a SYMMETRIC temperature check? |
04:24 | <ljharb> | thanks, i assumed so since i'd clicked it first |
04:25 | <waldemar> | Having several "yes" choices but only one "no" choice is too biased. |
04:25 | <waldemar> | And it leads to ambiguities like what we just encountered. |
04:26 | <ryzokuken> | Having several "yes" choices but only one "no" choice is too biased. |
04:26 | <Aki> | And it leads to ambiguities like what we just encountered. |
04:26 | <ryzokuken> | (in this case nobody would have picked that one, but in some cases I suppose they would) |
04:27 | <waldemar> | Other committees use SF, F, Neutral, A, SA |
04:28 | <bakkot> | Yeah, we kind of use it for different things sometimes |
04:28 | <bakkot> | for something like this it should definitely be symmetric |
04:28 | <Aki> | i accidentally skipped shane in the queue, sorry |
04:28 | <ryzokuken> | I don't need to speak |
04:28 | <HE Shi-Jun> | It seems most time we need a poll which could have more clear text for each choice. |
04:30 | <devsnek> | queue is on the wrong item |
04:30 | <Aki> | no it's not |
04:32 | <Jamie Kyle> | +1 I want this a lot |
04:37 | <ryzokuken> | what's wrong with base64 as spec'd in https://datatracker.ietf.org/doc/html/rfc4648 ? |
04:37 | <ryzokuken> | oh wait, it specs both urlsafe and not |
04:37 | <Aki> | my mic just crashed |
04:38 | <devsnek> | ryzokuken you just got played |
04:38 | <Aki> | 🤦🏻♀️ |
04:38 | <ryzokuken> | but we can choose one, I'd prefer urlsafe |
04:38 | <Aki> | ryzokuken: ☝️ |
04:38 | <Aki> | a little help |
04:38 | <ryzokuken> | since JS is so strongly tied to the web |
04:38 | <ryzokuken> | Aki: got this |
04:39 | <Michael Ficarra> | note-takers: if you don't know someone's initialism, either write their full name or look it up in delegates.txt |
04:39 | <Michael Ficarra> | please don't just make a guess at it |
04:41 | <Justin Ridgewell> | Aki: Can you advance the queue to devsnek's topic |
04:41 | <ryzokuken> | Justin Ridgewell: need to go for the clarifying questions first, otherwise we'd lose them |
04:42 | <Aki> | uhh no but |
04:42 | <Aki> | did i fix it? |
04:42 | <Justin Ridgewell> | devsnek: There was a discussion about TextEncoder , but it was blocked because it's already standardized by HTML |
04:42 | <devsnek> | can we just move that into our spec then |
04:43 | <ryzokuken> | oh you did |
04:43 | <devsnek> | i'm tired of it being slow |
04:43 | <ryzokuken> | I just realized that we can move stuff up and down, sorry my bad |
04:43 | <Justin Ridgewell> | The objector said that would be very rude of us to do. |
04:44 | <devsnek> | so whatwg is against moving textencoder to tc39? |
04:44 | <Justin Ridgewell> | ¯\_(ツ)_/¯ |
04:44 | <Justin Ridgewell> | This was several years ago at this point |
04:49 | <HE Shi-Jun> | many time , u need buffer.tobase64Buffer() ... |
04:49 | <HE Shi-Jun> | now people have to write new TextEncoder('utf8').encode(buffer.toBase64()) ... |
04:51 | <HE Shi-Jun> | I hope engine at least could optimize that usage. |
04:51 | <ptomato> | FWIW, moving TextEncoder/TextDecoder to 262 would be quite helpful to all the software that embeds a JS engine, such as GNOME, or 0AD |
04:51 | <ptomato> | (or, at least, I can say that for GNOME it would, just assuming about the others) |
04:51 | <ryzokuken> | and Node |
04:51 | <HE Shi-Jun> | both node.js/deno implemeneted TextEncoder/TextDecoder |
04:51 | <ryzokuken> | yeah |
04:51 | <devsnek> | its slower than it should be though |
04:52 | <ptomato> | GNOME is implementing it as well, but it would be nice to delete that code |
04:53 | <HE Shi-Jun> | Actually it's hard to say the platforms implementation TextEncoder/TextDecoder are all same and correct :) |
04:53 | <Michael Ficarra> | I'm surprised to hear anyone say this doesn't meet the bar for usefulness |
04:53 | <ryzokuken> | another reason why TextEncoder should be in the engine |
04:54 | <littledan> | Temporal has lots of complexity; I'm not sure where the line should be for complexity and the standard library. |
04:54 | <legendecas> | Actually it's hard to say the platforms implementation TextEncoder/TextDecoder are all same and correct :) |
04:54 | <ryzokuken> | legendecas: but non-web hosts don't run WPT, right? |
04:54 | <devsnek> | wpt is useless because they refuse to write tests in a way that can be used by non-web hosts easily |
04:54 | <ryzokuken> | I think Node was planning to, atleast partially |
04:54 | <legendecas> | node.js do |
04:54 | <ryzokuken> | yeah |
04:54 | <devsnek> | node.js can barely run a very small subset of wpt tests |
04:55 | <devsnek> | using a very complex test harness that took a long time to implement |
04:55 | <Michael Ficarra> | we've used WPT in a non-web context with some success FWIW |
04:55 | <littledan> | yeah I like the idea of implementing web APIs outside of the web, sharing tests, etc |
04:55 | <Jamie Kyle> | There are plenty of JS features I've needed to create my own versions of, but that doesn't detract from the usefulness of having a version of them in the language |
04:56 | <leobalter> | I might not be able to be in the call for the rest of day, but I register here that I'm in sync with littledan's presentation and I strongly support the Module Blocks/fragments proposal. It is an amazing opportunity to explore with Realms but also without it. There is much to config and many realms we use today at Salesforce. If we have module blocks, this will be a considerable removal of network requests. Think about configuration that needs to be loaded per realm and out application uses many many many realms. Bundling still requires code injection so Module Blocks allows a much smoother configuration for us. |
04:56 | <ryzokuken> | There are plenty of JS features I've needed to create my own versions of, but that doesn't detract from the usefulness of having a version of them in the language |
04:57 | <devsnek> | uuid was blocked from being in stdlib |
04:57 | <HE Shi-Jun> | oh? is uuid blocked? ... what a pity |
04:58 | <ryzokuken> | indeed |
04:58 | <Michael Ficarra> | devsnek: it wasn't blocked, the champion felt it was faster to go through a different SDO |
04:58 | <devsnek> | oh, interesting |
04:58 | <ryzokuken> | well, I do believe that in this case it makes more sense to be in WebCrypto |
04:58 | <Michael Ficarra> | which is a bummer |
04:58 | <shu> | it was actually faster, it wasn't just they felt it was faster |
04:59 | <littledan> | well, Intl was faster to do in TC39, when the web standards community shut it down initially |
04:59 | <littledan> | there's no consistent pattern here |
04:59 | <littledan> | there are lots of things that we manage to do pretty fast in TC39 |
04:59 | <littledan> | I don't think we would've done crypto faster, though |
04:59 | <ryzokuken> | does WICG qualify as an SDO? I don't think you need to do any consensus-building there? |
05:00 | <HE Shi-Jun> | WICG is only community group? |
05:00 | <devsnek> | i think we should make a "javascript but for real platforms" spec, sort of like wasi, where it has all the useful apis we don't allow into js because of its abstract target |
05:01 | <ljharb> | i thought the issue with uuid was that folks on TC39 actively blocked adding anything that's in WebCrypto to the language? |
05:02 | <Jamie Kyle> | I just want to reiterate my support for this proposal. I think its very useful, and I'd be happy for it to have options. I think in general we should support adding more Clearly Useful Things to JS |
05:03 | <HE Shi-Jun> | I think we all agree adding useful things , the problem is how to define "useful" :) |
05:04 | <Jamie Kyle> | I dont think the pushback was that it was not useful |
05:11 | <devsnek> | i think that's still statically verifiable in the split form |
05:12 | <bakkot> | many time , u need buffer.tobase64Buffer() ... |
05:13 | <devsnek> | a buffer where the bytes are numbers representing ascii characters of base64? |
05:13 | <HE Shi-Jun> | ok i should say "some time" not "many time" :) |
05:14 | <bakkot> | but we can choose one, I'd prefer urlsafe |
05:14 | <ryzokuken> | oh, fair point |
05:15 | <devsnek> | the queue is behind |
05:16 | <ryzokuken> | devsnek: fixed |
05:17 | <leobalter> | Why my topic was removed? |
05:17 | <leobalter> | Adding it again |
05:18 | <Aki> | oops. i accidentally nexted you |
05:18 | <Aki> | my b |
05:18 | <leobalter> | now Mark's topic seems to be gone :) |
05:18 | <Michael Ficarra> | leobalter: you're on the queue twice |
05:18 | <ryzokuken> | I see all topics |
05:19 | <ryzokuken> | 2 by leo 2 by mark 1 by hax |
05:19 | <Michael Ficarra> | same ryzokuken |
05:19 | <devsnek> | one by snek one by daniel |
05:19 | <Aki> | i screwed up. everyone refresh |
05:19 | <ryzokuken> | ...and counting |
05:19 | <Aki> | sorry i broke it |
05:20 | <ryzokuken> | fwiw, it feels like cheating since I work with Dan, but strong +1 from me too 😀 |
05:20 | <HE Shi-Jun> | can module variable be passed to other functions? |
05:21 | <devsnek> | yes, there was an example in the presentation passing it to new Worker() |
05:21 | <HE Shi-Jun> | so u could also return a module variable from another function? |
05:21 | <devsnek> | its a value yes |
05:23 | <leobalter> | Michael Ficarra: tcq seemed broken, perhaps? The first topic I added was gone, same with Mark, I added it again after it disappeared for me. |
05:24 | <Michael Ficarra> | leobalter: try refreshing next time that happens |
05:25 | <leobalter> | well, I've never seen that issue before. I thought someone deleted it so I added again as I wanted to add it before the queue got crowded. |
05:25 | <leobalter> | I'll surely try a refresh next time |
05:27 | <Aki> | ten minutes |
05:28 | <HE Shi-Jun> | it seems I was skipped in the queue :) |
05:29 | <HE Shi-Jun> | Anyway, my question is about could I write code like "function x() { return module {} }; const m = x(); import {} from m;" I suppose it should not allowed? |
05:30 | <devsnek> | that would not work, static imports happen before evaluation |
05:30 | <devsnek> | you could use dynamic import though |
05:33 | <HE Shi-Jun> | yeah I guess it should not allowed , but it's a little weird that module m{}; import x from m works but let m = module m{}; import x from m not. |
05:33 | <danielrosenwasser> | "Strong support MICROPHONE EMOJI - he must really want to speak!" - Aki |
05:33 | <Aki> | hahahaha |
05:34 | <leobalter> | Aki: can we do a temperature check? Assuming Daniel is ok with that |
05:35 | <devsnek> | yeah I guess it should not allowed , but it's a little weird that |
05:35 | <HE Shi-Jun> | it's like to say, let m = module {} suddenly make m become dynamic :) |
05:35 | <HE Shi-Jun> | devsnek: import/export could be everywhere... |
05:35 | <devsnek> | yeah but they're always hoisted |
05:36 | <bakkot> | fwiw, that does kind of already happen with functions:
|
05:36 | <bakkot> | so there is at least a little precedent |
05:36 | <leobalter> | phoddie: I can see 2 entries from you on the queue, first is "Like this direction." |
05:36 | <leobalter> | is this the one missing for you? |
05:36 | <leobalter> | (I just learned that a refresh should bring it back) |
05:37 | <devsnek> | i feel like this proposal could be a cool opportunity to introduce nested import syntax |
05:37 | <Jamie Kyle> | I would really like to see some syntax like what exists in Rust to import from the enclosing "parent" module
|
05:37 | <devsnek> | import { react: { useState } } from 'bundle' |
05:37 | <HE Shi-Jun> | @bakkot I think it's a differnt problem. we can remove the inner f or m |
05:38 | <devsnek> |
|
05:38 | <Jamie Kyle> | devsnek: Yeah I raised it :P |
05:38 | <HE Shi-Jun> | @devsnek do we really need nested import? consider we have the url syntax which already have nested path for module... |
05:38 | <Jamie Kyle> | https://github.com/tc39/proposal-js-module-blocks/issues/34 |
05:39 | <devsnek> | oh on the other proposal repo |
05:40 | <leobalter> | phoddie: YES! |
05:40 | <leobalter> | dormant modules |
05:40 | <leobalter> | they are statically parsed, but runtime evaluated on demand |
05:40 | <devsnek> | @devsnek do we really need nested import? consider we have the url syntax which already have nested path for module... |
05:41 | <Jamie Kyle> | littledan: thank you for pursuing this! |
05:42 | <Aki> | I STILL THINK ABOUT THIS CONVERSATION ALL THE TIME |
05:42 | <HE Shi-Jun> | import {x: {y: {z}}} from 'module' vs import z from 'module/x/y' , seems no much difference :P |
05:42 | <Aki> | december 2019 |
05:42 | <Aki> | salesforce |
05:42 | <Aki> | fltering |
05:42 | <devsnek> | lol |
05:42 | <Aki> | like literally last week i was thinking about this |
05:43 | <devsnek> | so glad we're finally going to be getting array filtering in js |
05:43 | <Aki> | -_- |
05:43 | <devsnek> | oh this isn't tdz oops |
05:44 | <HE Shi-Jun> | About the array empty slot issue previously mentioned, it seems filterReject should follow filter (which skip the empty slots) but not sure about the groupBy . |
05:44 | Hemanth H.M | remembers stating the coffee filter example 😅 |
05:45 | <ljharb> | why filterReject instead of just reject ? |
05:45 | <HE Shi-Jun> | ljharb: I don't know. It's the naming bikeshed issue. Actually I don't like reject or filterReject because it make me confused with promise reject... |
05:46 | <Jamie Kyle> | I am used to the name reject cause of https://docs-lodash.com/v4/reject/ |
05:46 | <ljharb> | also ruby |
05:47 | <HE Shi-Jun> | Personally I prefer filterOut or filterNot (which is used by kotlin) |
05:47 | <Jamie Kyle> | Should groupBy() return a Map? |
05:47 | <ljharb> | i'd prefer a null object over a map |
05:47 | <ptomato> | is "people who are like me" an unchangeable designation? personally I had the wrong intuition about "filter" the first time I encountered it (not in JS) but quickly got used to it |
05:48 | <HE Shi-Jun> | ptomato: So it's a stage 1 issue, and i remember we already had 40 mins arguments in stage 1 meeting... |
05:48 | <Jamie Kyle> | i'd prefer a null object over a map groupBy() to get { true: [...], false: [...] } |
05:49 | <ljharb> | i'd expect people do do condition ? 'yes' : 'no' or similar tho, rather than relying on that |
05:49 | <Jamie Kyle> | Why should it be limited to stringifiable values though? |
05:50 | <ljharb> | fair point, i'd expect returning a symbol to work too (for the object case) |
05:51 | <devsnek> | objects can have symbol keys jordan |
05:51 | <ljharb> | in general tho maps/set aren't sufficiently useful due to their lack of tons of helper methods |
05:51 | <Jamie Kyle> | well we should definitely fix that! |
05:52 | <bakkot> | holes = undefined here |
05:52 | Hemanth H.M | got on to a tangent over array comprehensions |
05:52 | <devsnek> | groupby = runs? |
05:52 | <shu> | apparently it is in python |
05:52 | <bakkot> | I prefer objects because getting things from them is much more convenient |
05:53 | <bakkot> | in particular let { a, b } = list.groupBy(whatever) is nice with objects, does not work with Map |
05:53 | <devsnek> | skip the holes! |
05:53 | <iain> | Rust's group_by (in itertools) also does runs |
05:54 | <shu> | could bikeshed the name |
05:54 | <shu> | i believe it is what non-programmers call "sorting" |
05:54 | <shu> | so maybe sort2 |
05:55 | <devsnek> | lol |
05:57 | <bakkot> | for the notes, who is speaking? |
05:57 | <bakkot> | got it thanks |
05:57 | <danielrosenwasser> | groupBy returning an object is only useful for object keys (obviously I guess) which seems like a problem. Cute for partition and works almost well with static type systems, but very inconsistent with broader use-cases that other languages implement for groupBy |
05:59 | <devsnek> | my tcq doesn't match what's on the screen |
06:00 | <devsnek> | reloading doesn't fix |
06:00 | <iain> | Mine matches |
06:00 | <ryzokuken> | mine too |
06:00 | <Hemanth H.M> | I resonate strongly with Michael |
06:01 | <Jamie Kyle> | I agree that select would have been a better name for filter which would have made a reject method intuitive. But he combination of filter+reject/out feels like more mental overhead for me to sort out, it has a double negative feel to it to me that I'd second guess all the time |
06:04 | <danielrosenwasser> | I agree with that ^ but I also feel like there is a legitimate use-case for some sort of rejection filter. I think we've had to write a not helper function so we can write .filter(not(someFunc)) |
06:06 | <ljharb> | what about Map.groupBy(iterable, callback) versus Object.groupBy(iterableOrArraylike, callback) ? |
06:07 | <Jamie Kyle> | iain: Yeah... Based on some of discussions elsewhere though, I feel like we overestimate the problem of two similarly named methods on different objects doing different things as a serious source of confusion for users |
06:07 | <Hemanth H.M> | or as Daniel mentioned, if we have a not function, we could says odd = not(isEven); and then filter on odd |
06:07 | <Michael Ficarra> | ljharb: can't do an iterable, only finite structures |
06:07 | <Jamie Kyle> | A not global sounds hard to add |
06:08 | <ljharb> | ljharb: can't do an iterable, only finite structures |
06:08 | <ljharb> | if it's infinite then it'd loop forever, which is what happens almost everywhere if you have an infinite iterator anyways |
06:08 | <Hemanth H.M> | I guess, they meant a local function in that example and not a global not |
06:09 | <Michael Ficarra> | ljharb: because groupBy on infinite structures is commonly understood to have the Python/Haskell semantics discussed earlier |
06:10 | <ljharb> | meh, ok |
06:11 | <HE Shi-Jun> | filter(not(x)) not really solve the original motivation (though I don't strongly support that) |
06:11 | <ljharb> | aki++ |
06:12 | <Hemanth H.M> | reject conflicting with Promise.reject is a legit concern |
06:13 | <littledan> | I don't think it's useful to be so particular about Stage 1 requirements |
06:13 | <Hemanth H.M> | Stage - 0 is an idea Stage - 1 defining the problem Stage - 2 defining the solution ^ sounds good? |
06:13 | <littledan> | (contradicting myself, I do think an explainer is a requirement for a Stage 1 proposal) |
06:13 | <ljharb> | stage 1 also means that TC39 wants to keep discussing/solving the problem |
06:14 | <devsnek> | Stage - 0 is an idea |
06:14 | <Jamie Kyle> | When I was exploring the name Object.has vs Object.hasOwn I did an exploration into methods named the same thing on different objects in 262+web apis, there are a number of examples, and I could not find any confusion about them on github or stack overflow. I really don't think there's an issue with Promise.reject and Array#reject being named the same thing |
06:15 | <littledan> | wasn't handling of non-property-keys an open question for groupBy? |
06:15 | <littledan> | I agreed with Mark's point that R&T interaction is important |
06:15 | <HE Shi-Jun> | Jamie Kyle: It may be a unnecessary burden for newbie, and especially for non-English speakers. |
06:16 | <Hemanth H.M> | 2019 December notes on array select-reject for stage-1 -> https://github.com/tc39/notes/blob/master/meetings/2019-12/december-4.md#array-selectreject-for-stage-1 |
06:17 | <ljharb> | Justin Ridgewell: once you name and make a repo for groupBy please hmu so i can update the proposals table |
06:17 | <littledan> | +1 to Mark's and ptomato 's comment about being unenthused about filterReject |
06:17 | <HE Shi-Jun> | Jamie Kyle: especially Object.has/keys would have a subtle semantic difference with Map/Set.has/keys (even it may not cause many problems in practice) |
06:18 | <Jamie Kyle> | To be clear I'm not proposing renaming hasOwn to has again |
06:19 | <devsnek> | Object.has implies it returns a list of ha that the object contains |
06:19 | <Jamie Kyle> | But there are examples of identically named methods that do distinct things already and I dont see confusion about it |
06:20 | <danielrosenwasser> | Yeah, I don't have a strong opinion on the name, but Math.log and console.log have different contextual meanings. Promise.reject doesn't really throw a wrench in anything here. |
06:20 | <littledan> | module fragments might not be needed for tomorrow btw |
06:20 | <littledan> | I guess I was asking for an extension because I misunderstood the state of the queue |
06:21 | <danielrosenwasser> | I guess this is relevant again https://twitter.com/drosenwasser/status/1139665079324925952 |
06:23 | <HE Shi-Jun> | danielrosenwasser: sometimes it's unavoidable... but if we can we should avoid such things I believe. And console.log is not TC39 specced :) |
06:24 | <Jamie Kyle> | Name a javascript developer that doesnt use console.log :P |
06:25 | <danielrosenwasser> | HE Shi-Jun: So you're saying my proposal to add log10 , log2 and log1p to console would be better in WHATWG? 😄 |
06:27 | <danielrosenwasser> | Okay no more jokes, have a good night/day everyone! |
06:55 | <HE Shi-Jun> | Name a javascript developer that doesnt use console.log :P |
07:05 | <HE Shi-Jun> | I have been asked a question about proper tail call and I need some help. |
07:05 | <HE Shi-Jun> | ProJS 4th edition 4 has a chapter introduce proper tail call which was added in ES6, and the book says that closure can't get PTC, but I can't find it in the spec (maybe I missed it) and it seems safari (the only engine implement PTC) also don't have such limitation. |
07:06 | <HE Shi-Jun> | Is that the error of the book? |
07:13 | <bakkot> | The spec definitely doesn't make mention of such a restriction, so I think the book is wrong. |
07:14 | <bakkot> | I'm also having a hard time coming up with an example where it would even be observable. |
07:14 | <iain> | The comment in the example says that closures are not supported, but if you read the text above, it says "the tail call function is not a closure that refers to variables in the outer function's scope" |
07:16 | <Aki> | apologies in advance, incoming noise. i've tested the API as far as i can on a test channel, now i need to do it on this channel oh god i hope i don't break it |
07:18 | <Aki> | well that was an unexpected outcome |
07:29 | <HE Shi-Jun> | I'm also having a hard time coming up with an example where it would even be observable. new Error and check the error.stack to see whether the caller is in the stack. Though stack is not specced so hard to say whether it reflect the truth. |
07:31 | <HE Shi-Jun> | (BTW, this is also a reason that I prefer STC than PTC, because PTC may affect the error stack by accident and cause error collection and unification issue in real world.) |
07:31 | <ryzokuken> | well that was an unexpected outcome |
07:32 | <Aki> | both? |
07:32 | <ryzokuken> | hah |
07:32 | <ryzokuken> | schrodingers room |
07:33 | <Aki> | i was running a PUT to update perms on the room, apparently i can't reduce perms of someone equal to me, which makes sense i guess |
15:22 | <Richard Gibson> | this was fun... turns out that JSC tokenizes non-ASCII non-Latin1 WhiteSpace characters after a regular expression literal as part of its flags, and XS doesn't recognize them as WhiteSpace at all |
15:33 | <bakkot> | fun |
15:33 | <bakkot> | sounds like a good test262 test |
16:01 | <devsnek> | scary |
16:10 | <phoddie> | Richard, thanks for the excellent report. Much appreciated. Must not have been caught by test262 (not in our list of known RegExp issues). |
17:07 | <Richard Gibson> | yep. I opened a Test262 issue, and will try to fix it now |
17:30 | <Richard Gibson> | leobalter: would you have any time to help me understand best practices for the above? |
19:01 | <bakkot> | shu: a passing thought: now that resizable buffers has exposed the notion of detaching buffers to non-threaded code, maybe buffer.toBase64 should have an option to detach the original buffer as well |
20:23 | <leobalter> | Richard Gibson: link? |
20:23 | <leobalter> | or let me find it... |
20:29 | <leobalter> | ok, I agree with phoddie , the report is great! We have tests in Test262 for whitespace and LT but most of them are actual characters instead of escapes or string evaluation. In this case, one test file with all the cases would blow without proper information, so I'd split into several files, each one for each character. |
20:32 | <Richard Gibson> | right, I want to know where in the repo structure to do that and what the files should look like. I'm assuming this will be templated |
20:34 | <leobalter> | I sse some files just use the escaped character, which might help the generation |
20:34 | <leobalter> | like var\u000Ax; |
20:35 | <leobalter> | My first guess would be to use test/language/literals/regexp but I wonder if that's more related to ASI or something else. I need to re read the original issue |
20:36 | <Richard Gibson> | it's related to properly recognizing WhiteSpace and LineTerminator as insignificant in the stream of input elements, specifically after a regular expression literal |
20:38 | <leobalter> | this folder should be fine... see regexp-first-char-no-line-separator.js in there |
20:38 | <leobalter> | it treats <LS> inside, so we can extend texts for <LS> outside |
21:02 | <leobalter> | Richard Gibson: I created a stub here but it's been too long I don't use the generation tool. Python is not happy about it. I'll send some code if I get it running |
21:05 | <Richard Gibson> | basically, I want help so that I can contribute more meaningfully for this and other issues. Right now I don't understand best practices well enough to do so. |
22:53 | <shu> | bakkot: re: detaching original buffer, what's the use case there to detach? |
22:54 | <bakkot> | just so that you don't have to keep both in memory |