00:30:32  * AtumTquit (Quit: AtumT)
01:44:34  <Bakkot>ljharb / zenparsing: I forget when I last pinged you about this, but, it would be good to get #1158 and #1137, or equivalents, in for 2019. 1158 needs updated wording but is waiting on 1137.
02:06:10  * gibson042joined
04:24:18  * gibson042quit (Quit: Leaving.)
04:25:36  * keith_millerjoined
04:55:01  * ephemera_quit (Remote host closed the connection)
04:56:15  * ephemera_joined
05:35:39  * jmdyckquit (Remote host closed the connection)
06:08:49  * keith_millerquit (Quit: My MacBook has gone to sleep. ZZZzzz…)
06:11:20  <ljharb>Bakkot: i'll add 1137 to the list for next week's meeting; things don't "transition" until after may tho, so it's still in bterlson's queue atm
06:14:35  <devsnek>have y'all seen that cherow got a makeover
06:14:43  <devsnek>(https://github.com/cherow/cherow btw)
06:15:48  <ljharb>O.o what is cherow
06:16:05  <TimothyGu>a better acorn that passes test262
06:16:19  <TimothyGu>just like how acorn was a better esprima
06:16:28  <ljharb>if it's better, has there been an attempt to get eslint and/or babel to use it?
06:16:34  <devsnek>its still in development
06:16:39  <devsnek>two months ago it barely passed es5
06:17:20  <devsnek>but its estree compatible so should be good to slide into anything
06:18:34  <ljharb>ah k
06:18:42  <ljharb>slide it into eslint core then :-p
06:21:20  <devsnek>i've become really surprised with how loose all the big parsers are (acorn, babel, etc)
06:21:28  <devsnek>they all miss a lot of context and early errors
06:21:57  <TimothyGu>in case of Acorn: https://github.com/acornjs/acorn/issues/created_by/TimothyGu
06:27:49  <Bakkot>babel has much more work because of all the syntax extensions it has to do
06:28:03  * keith_millerjoined
06:28:10  <Bakkot>a while back, as part of test262-parser-tests, I started a project to run all the parsers against it and file bugs
06:28:30  <Bakkot>but there were so many and I never got back to it
06:29:40  <devsnek>its kinda weird how none of them actually run against test262 though
06:29:44  <Bakkot>shift does!
06:29:54  <Bakkot>https://github.com/shapesecurity/shift-parser-js/tree/8add44f4289b215eac555412d75547f5d2137133/test/test262
06:30:07  <devsnek>ok none of the ones with es2019
06:30:23  <Bakkot>es2019 isn't a thing yet
06:30:31  <devsnek>es2019 draft
06:31:04  <devsnek>tc39.github.io is the only good source of truth
06:31:52  <Bakkot>we track releases of the spec because AST changes are breaking, and it makes sense to bundle those
06:32:27  <devsnek>is shift a cst
06:33:01  <ljharb>why are ast changes breaking? aren't they additions?
06:33:01  <Bakkot>no, though it has an API which lets you query the location information for an AST node and also get comments with locations
06:33:25  <devsnek>yeah if its an ast i don't think there would be breaking changes
06:33:33  <Bakkot>ljharb: if I have something which consumes an AST and assumes that e.g. `catch`'s binding is necessarily there, that will break if that stops being the case
06:33:46  <devsnek>oh yeah i guess that broke eslint
06:33:52  <Bakkot>yes it did!
06:34:00  <Bakkot>though this is more obvious in the Java version, where the AST nodes are represented by Java types which of course must match precisely
06:34:11  <ljharb>Bakkot: ah, true. i suppose if the edition year were an option it'd be fine
06:34:27  <Bakkot>we just publish new major versions /shrug
06:35:04  <devsnek>oh yeah edition year
06:35:15  <devsnek>why did eslint break again
06:35:15  <ljharb>Bakkot: seems unfortunate, can't look at multiple editions at once
06:35:47  <Bakkot>I think npm will let you depend on multiple versions of a package, these days
06:35:55  <devsnek>oh you can add a custom parser to eslint
06:35:59  <Bakkot>also though why would you want that
06:36:01  <devsnek>so it would have been people with babel-eslint
06:36:55  <ljharb>Bakkot: it won't
06:36:58  <ljharb>Bakkot: not at the top level
06:37:28  <ljharb>you'd want that if you wanted to provide a configuration option to your consumers and have shift as a dep - like eslint, babel, or every other use case for a parser so far :-)
06:37:52  <ljharb>why wouldn't you want that?
06:39:17  * keith_millerquit (Quit: My MacBook has gone to sleep. ZZZzzz…)
06:39:19  <Bakkot>Maintanence burden, mainly.
06:39:32  <ljharb>well yeah that's why you wouldn't want it, but why wouldn't every user want it
06:40:09  <ljharb>i mean, specifically, no extant tool in the ecosystem could switch to shift without it - so it seems a pretty important thing to have if adoption is a goal
06:40:10  <Bakkot>because config = bad, just give me the thing which parses the most programs, generally speaking
06:40:34  <Bakkot>if we made breaking changes to old parses, which we do occasionally in obscure unicode things but not otherwise, I'd understand
06:40:37  <ljharb>config isn't bad, as long as the defaults are reasonable, config id very very good
06:41:11  <Bakkot>eh, I mean, I don't want to make absolutist statements, but it certainly is not a universal good
06:41:17  <ljharb>nor a universal bad
06:41:26  <Bakkot>I think one of the best things prettier has done for the ecosystem is push back on config options
06:41:55  <Bakkot>anyway, no, adoption isn't really that much of a goal, at least not into existing projects like eslint
06:41:56  <ljharb>and the lack of configs is why its adoption is as low as it is, and prettier has added way more config options than its creator ideologically promised
06:41:58  <ljharb>gotcha
06:42:11  <devsnek>acorn defaults to es5.1 :(
06:42:27  <Bakkot>main goal is providing a correct parser with a sane AST for ourselves and anyone else who wants that, like the binast people
06:43:03  <Bakkot>also reducer-style transforms, which are _so_ much nicer than visitors, jeeze
06:43:04  <ljharb>devsnek: still the best default, based on most browser support targets
06:43:14  <Bakkot>speaking of, just updated the website! http://shift-ast.org/reducer.html
06:43:15  <devsnek>ljharb: parsers should support all the way up
06:43:23  <devsnek>if acorn generated code i would agree with you
06:43:44  <ljharb>devsnek: i agree that it should be possible, but i think es5 is still the proper default, and will be for awhile
06:43:55  <Bakkot>ljharb: not sure why "this JS is targeted for untransformed execution on large companys' browser support targets" is a good assumption
06:44:15  <devsnek>reducer is cool
06:44:47  <ljharb>Bakkot: it's the safest
06:45:19  <ljharb>Bakkot: because with transforms and old code, it still works. with a default of "modern" and no transforms, it breaks.
06:45:29  <ljharb>(for users of old browsers, which are still plentiful)
06:45:51  <Bakkot>were that the goal it should also refuse programs which parse incorrectly on browers with nontrivial adoption, which I think it absolutely should not do
06:45:57  <Bakkot>if that's what you want, write a rule for it
06:46:33  <ljharb>tbh i think eslint should do that by default. are you aware of any patterns it parses that fail on browsers?
06:46:49  <ljharb>imo the default should be what will maximize "where it works"
06:47:00  <ljharb>anything that restricts where it can work should be opt-in
06:47:11  <ljharb>that doesn't mean the defaults have to work everywhere, ofc.
06:47:23  <devsnek>as long as the parser doesn't think `let let = class let {}` is valid
06:47:25  <devsnek>i'm happy
06:48:22  <Bakkot>({゛: "゛"}) failed on safari relatively recently
06:48:43  <Bakkot>`!await test()` too
06:48:44  <ljharb>then it shouldn't be permitted by eslint nor outputted by babel ¯\_(ツ)_/¯
06:49:06  <Bakkot>there's also a billion comment-parsing bugs old browsers, esp. re: html comments
06:49:07  <ljharb>academic correctness isn't important with actual workflow tools; actual correctness is
06:49:37  <devsnek>omg that object literal is evil
06:49:44  <devsnek>why is that a valid identifier
06:49:59  <Bakkot>ljharb: your assumption is that the thing people want from eslint is that code run through it should work on browsers
06:50:10  <Bakkot>but, I claim, that is very far from the majority use case
06:50:36  <ljharb>i can't conceive of what other use case there is
06:50:46  <ljharb>the point is to maximize correctness at later runtime
06:51:09  <devsnek>i hear there's this cool thing called node.js
06:51:13  <devsnek>which runs code on the server
06:51:28  <devsnek>and that it supports like `const` and `class` and stuff
06:51:30  <Bakkot>ljharb: more things in heaven and earth etc
06:52:27  <ljharb>Bakkot: sure, but what use cases do you think people run eslint for that aren't maximizing runtime correctness?
06:52:38  <ljharb>devsnek: ok well, implementations, not just browsers
06:52:42  <Bakkot>maximizing correctness after being run through babel and/or uglify
06:52:44  <devsnek>Bakkot: i disagree with your usage of that quotation
06:52:49  <Bakkot>also some style stuff
06:53:04  <ljharb>Bakkot: O.o ok well, running eslint on compiler output is in *no way* a common use case, for one
06:53:14  <Bakkot>sorry, no, the other way around:
06:53:16  <ljharb>Bakkot: and "style stuff", sure, but that overlaps
06:53:36  <Bakkot>maximizing correctness of A after A is run through babel
06:53:50  <Bakkot>not maximizing correctness of the output of babel on A
06:53:54  <ljharb>i agree that babel/uglify/etc output is what actually needs to work, but the presumption is that you can eslint your input, and those tools won't output things that break
06:54:18  <ljharb>in no way is it common to run eslint on any code but the code you author (what gets sent to babel)
06:54:35  <rkirsling>^ yeah that would be wacky
06:54:36  <Bakkot>I didn't mean to imply people were running babel on code comming out of babel
06:54:37  <Bakkot>just the opposite
06:54:38  <ljharb>i'm sure it's done, but basically nobody actually runs eslint on babel output. if you don't trust babel implicitly, don't use it
06:54:54  <ljharb>once you put your code into a tool, you never run anything on it after that, typically
06:55:00  <ljharb>babel, uglify, webpack, etc
06:55:03  <ljharb>you just implicitly trust irt
06:55:06  <ljharb>*it
06:55:07  <Bakkot>yes, I know, that is not a point of disagreement
06:55:35  <Bakkot>my point is that eslint etc should assume their target is those tools, not browsers
06:55:38  <ljharb>ahhh
06:55:41  <ljharb>ok sure, perhaps
06:55:47  <ljharb>but then the "no build process" zealots will pop up
06:56:02  <ljharb>and even tho i'm not one, i'd argue that the safe default is not to assume someone is using those tools
06:56:07  <ljharb>since there are plenty of people that aren't
06:56:21  <Bakkot>"not to assume someone is using those tools and also that they are intending to target IE9"
06:56:30  <Bakkot>I think this is mostly a disagreement about what "safe" means.
06:56:50  <ljharb>without explicit info, the safe thing is to assume someone is targeting every browser currently used by anyone
06:56:57  <ljharb>IE 6, eg
06:57:23  <ljharb>it's reasonable to pick an arbitrary cutoff, tho, and by many metrics that would still include IE 9 for sure, and possibly even IE 8
06:57:26  <Bakkot>ok, I guess it is also a disagreement about the extent to which that sense of "safe" is a good default for a tool, as opposed to "useful"
06:57:37  <ljharb>"works" is the most useful
06:57:54  <ljharb>but sure, those indeed might be points of disagreement :-)
06:58:03  <Bakkot>for me, "eslint works" means "eslint will run the linting rules"
06:58:23  <Bakkot>since that is what I want eslint to do; that is how I keep my code correct
06:58:38  <devsnek>to me, eslint should consider all the valid js as valid js unless you limit it
06:58:51  <Bakkot>if it refuses to parse a valid thing, it does not work
06:59:14  <Bakkot>if I want it to say a thing is bad, that is what _its rules_ are for, not the parser which runs before the rules
06:59:24  <devsnek>yep
06:59:45  <ljharb>Bakkot: what defines "valid" tho
07:00:06  <ljharb>if it's "the spec" then i'd point you to the overflowing "web reality" label on ecma262
07:00:31  <devsnek>i'd say engines have a lot of bugs
07:00:37  <Bakkot>the whole point of having a spec is to have a thing which tools can agree on as the single authority
07:00:42  <devsnek>and the spec has a lot of bugs
07:00:58  <Bakkot>"web reality" label doesn't have too many parsing things in it, IIRC, outside of some B33 bullshit and the `if (false) f() = 0` thing
07:01:06  <ljharb>fair
07:01:14  <devsnek>and a random subset of those things is what should work
07:01:25  <devsnek>leaning towards sane behaviour over engine bugs
07:01:34  <ljharb>but in practice the useful thing to consider "valid" is "what *actually* works", not "what a spec says" - it's just hopeful that those two agree
07:01:58  <devsnek>like function names
07:02:05  <devsnek>bad enough that Function.prototype has name as the empty string
07:02:13  <Bakkot>I think for a tool like eslint the right thing to consider "valid" is "what a spec says", and add rules which will error for valid inputs which are likely to run incorrectly on bugs
07:02:24  <Bakkot>*incorrectly on browsers because of bugs
07:02:26  <devsnek>but then engines go around putting empty strings on all the anonymous functions 😥
07:02:49  <Bakkot>"have rules which will error for valid inputs which are likely to have bugs" is after all the point of eslint
07:02:58  <ljharb>Bakkot: as long as there's a trivial way to configure that, then it's more of a bikeshed about the defaults
07:03:10  <Bakkot>well, yes.
07:03:18  <ljharb>Bakkot: but i'd still prefer that with no config, the only allowed code is what will work. the spec is pedantry that isn't useful to most.
07:04:01  <Bakkot>that really really seems wrong.
07:04:16  <ljharb>why?
07:04:19  <Bakkot>that is enforcing a rule at the wrong level.
07:04:36  <ljharb>why would the majority of users care about that distinction tho?
07:04:47  <devsnek>eslint doesn't know if you're targeting browsers or node or deno or mongoose
07:04:58  <Bakkot>because the majority of users do not actually care about that rule
07:05:01  <devsnek>so it should just consider all the valid js as valid
07:05:09  <ljharb>right. so the safe thing to do is to only allow the things that work on all of them as valid. not any of them.
07:05:14  <ljharb>Bakkot: i guess that's where we disagree
07:05:18  <Bakkot>specifically, the rule "will be valid syntax on at least 98% of browsers" is not a rule the vast majority of users care to enforce
07:05:18  <devsnek>lol
07:05:26  <Bakkot>because they intend to run through other tools downstream of eslint
07:05:26  <ljharb>Bakkot: i think what the majority of users don't care about is "the spec"
07:05:35  <ljharb>Bakkot: plenty of people don't use babel
07:05:53  <devsnek>i think most humans writing js go by mdn
07:05:55  <Bakkot>sure, but a majority? of those who a.) care about support for old browsers and also use eslint?
07:06:14  <Bakkot>"*and also b.) use eslint"; it is getting late, forgive my typos
07:06:34  <ljharb>whether they actively care about old browsers isn't relevant
07:06:42  <ljharb>that's the point. they should have to care about *breaking* them to break them
07:06:47  <ljharb>the default should be to support them
07:07:14  <Bakkot>that's a problem you have with users of the tools, not the tools they're using
07:07:37  <Bakkot>I do not think eslint ought to enforce that preference on all of its users by default
07:07:39  <ljharb>and the tools are working best when they can fix their users' problems :-)
07:07:48  <Bakkot>that is a very reasonable rule to enforce, as a configurable rule; it is not a very reasonable default
07:07:54  <ljharb>(note that i think we agree that regardless of the default, all of this should be configurable)
07:08:16  <ljharb>i think "breaking a website for any human being that's avoidable" is not a reasonable default
07:08:25  <ljharb>a single user is a person, and a site should work for them by default
07:08:50  <devsnek>why's your parse rule only got 98% then
07:08:53  <Bakkot>again, that is something you should take up with the users of the tools; the tools themselves should be agnostic to that position
07:09:27  <ljharb>i think that's where we disagree
07:09:42  <ljharb>and i think it's strange to claim tools should be agnostic while also claiming config is bag
07:09:53  <ljharb>agnostic tools allow every single facet to be configured :-)
07:09:54  <Bakkot>anyway, also I wouldn't want to configure the parser it uses, except to additionally support non-spec things if I wanted to opt in to those: I would want it to _accept_ those programs and then _emit errors because of rules run against them_.
07:10:30  <Bakkot>I don't think eslint having config for the rules it runs is bad, to be clear
07:10:42  <Bakkot>I think having config for things users shouldn't care about is bad
07:11:14  <Bakkot>e.g. it should not have config for "what es version does the parser support"; it should have config for "do you want a rule which will error for syntax from es2015 and later"
07:11:33  <Bakkot>but that should be a _rule_, exactly like all other rules
07:12:02  <Bakkot>because its intent is to catch correctness issues under a particular definition of correctness, exactly like all other rules
07:12:05  <ljharb>users don't care about the spec year
07:12:13  <ljharb>they care about their supported environments
07:12:15  <Bakkot>s/es2015/IE8/
07:12:24  <ljharb>sure, so like, babel-preset-env
07:12:42  <ljharb>and absent targets, i'm suggesting a broad default. perhaps it could require targets, and then no default would be needed
07:13:13  <ljharb>but virtually nobody cares about "es2015"; they care about "X target envs", modulo maybe running through specific tools
07:13:31  <Bakkot>"broad" should be wrt the input programs, so it can run rules on as many programs as it can.
07:13:47  <Bakkot>if users don't care about the spec year, surely the parser should not be configured by spec year?
07:13:53  <ljharb>i agree
07:13:53  <Bakkot>or, indeed, configured at all
07:14:00  <ljharb>it should be configured by targets
07:14:07  <ljharb>spec year is just the very imperfect way eslint is currently configured
07:14:14  <Bakkot>why is the parser the correct way to configure that?
07:14:20  <ljharb>because the targets have parsers?
07:14:35  <Bakkot>so? targets have interpreters too. so does eslint, in an abstract sense.
07:14:46  <ljharb>so "what can parse" should be the overlap of what will parse on every target
07:14:48  <Bakkot>the way you configure eslint's interpreter is with _rules_
07:15:00  <ljharb>the rules only get the chance to work if it parses
07:15:04  <Bakkot>right!
07:15:08  <Bakkot>so it should parse as many things as it can!
07:15:11  <Bakkot>so the rules get a chance to work!
07:15:17  <Bakkot>since the point of eslint is to run the rules!
07:15:22  <ljharb>no, i'm saying the rules don't matter if the code won't parse on your targets
07:15:47  <Bakkot>the parsing doesn't matter if the code won't run correctly on your targets because of a semantics issue which a rule would have caught.
07:16:12  <Bakkot>there is not meaningful difference between "wrong because it will fail to parse on your target" and "wrong because of other correctness issues of the type caught by rules"
07:16:19  <ljharb>ok, perhaps
07:16:33  <ljharb>but then the rules related to "what works on your targets" should be enabled by default :-)
07:17:32  <Bakkot>my preference would be for no rules to be enabled by default, which means the same thing for all users, whereas "what works on your targets" does not mean the same thing for most pairs of users.
07:17:59  <Bakkot>but sure, I am fine with that, as long as it parses those programs.
07:20:32  <Bakkot>(anyway, point is, I continue to think it's reasonable for parsers to only support es-latest and optionally extensions, in most cases)
07:22:36  <Bakkot>(I guess "error on all programs, because someone might not have javascript" might actually be a reasonable default too; it means the same thing for everyone and would at least get the point across that you will need to think about and configure which downstream use cases you care to support)
07:25:12  <ljharb>lol, i'd be fine with that if it forced everyone to provide targets, and included whatever kind of default-on enforcement to prevent code that won't run on them
09:13:53  * howdoijoined
10:08:48  * mgoljoined
11:44:54  * keith_millerjoined
11:55:01  * keith_millerquit (Quit: My MacBook has gone to sleep. ZZZzzz…)
13:25:45  * gibson042joined
13:39:04  * jmdyckjoined
14:28:06  * gibson042quit (Ping timeout: 258 seconds)
14:39:53  <bradleymeck>Bakkot: when doing static analysis I try to go for loosest mode with most common syntax extensions. if you force people to use the compiled form you get into weird renaming issues while showing them sources
14:41:46  * gibson042joined
14:55:28  <bradleymeck>who was going to propose freezePrototype?
14:58:14  <bradleymeck>nm XD
15:42:23  * keith_millerjoined
16:14:26  * jmdyckquit (Ping timeout: 250 seconds)
16:16:15  * jmdyckjoined
16:37:21  * cloudshujoined
17:13:41  * howdoiquit (Quit: Connection closed for inactivity)
17:19:43  * keith_millerquit (Quit: My MacBook has gone to sleep. ZZZzzz…)
17:35:57  * keith_millerjoined
17:43:40  * AtumTjoined
18:58:12  * keith_millerquit (Quit: My MacBook has gone to sleep. ZZZzzz…)
18:59:10  <rkirsling>littledan: did these questions of yours ever get answered? https://github.com/tc39/test262/pull/688#issuecomment-311759747
18:59:34  <rkirsling>I found the expected behavior here a little surprising: https://test262.report/browse/language/expressions/new/non-ctor-err-realm.js
18:59:39  <littledan>I don't see any answers there
18:59:57  <littledan>realm stuff is all a little surprisng
19:00:24  <rkirsling>yeah
19:02:56  * keith_millerjoined
19:06:30  * keith_millerquit (Client Quit)
19:06:36  * howdoijoined
19:08:41  * keith_millerjoined
19:10:38  * mgolquit (Quit: My MacBook has gone to sleep. ZZZzzz…)
19:22:58  <littledan>BTW, should we set up some place that, when people want to write about TC39 ,they can send their blog post or slide deck to us for review and corrections, if they want?
19:23:13  <littledan>this could help keep public information correct
19:23:44  <littledan>(though it's been pretty good lately even without coordination)
19:25:50  <Bakkot>how-we-work might be enough on its own? though I guess that's a little more internal-facing
19:31:43  <efaust>littledan: do you get the sense that there's a broad demand for this kind of interaction?
19:32:40  <littledan>this is a little different from how-we-work
19:32:56  <littledan>I'm talking about reviewing the content, not our working practices
19:33:58  <littledan>efaust: I'm in contact with a number of people who blog or give talks about TC39, and I sometimes review their work before it goes out, or put them in touch with proposal champions who do so. Formal channels could help distribute the load in the group and let more content creators have this kind of access, if we want to give it
19:34:42  <littledan>I don't think it's like everyone who does that stuff should be expected to get our sign-off, just like a possible way we could make ourselves available as a resource
19:38:20  <efaust>oh, I didn't think you were proposing a watchdog :P
19:44:50  * akirosejoined
19:57:34  <Domenic>So I'm starting to see the need for a fairly common operation which goes async iterator -> promise<array>, similar to how `Array.from(i)` or `[...i]` works on sync iterators
19:58:47  <Domenic>If we were to standardize this, the best spelling I can think of is `ai.collect()`; there's no `XXX.from(ai)` or `[...await... i]` syntax that makes sense
19:59:48  <Domenic>This naturally raises the question as to whether we should add `i.collect()` to `Iterator.prototype` as well, because two ways to do something is not enough :-/.
19:59:51  <Domenic>Anyone have thoughts, either on spelling, or want to be a champion for this?
20:00:07  <Bakkot>I feel like `Promise.all` could be adapted to work there?
20:00:26  <Domenic>Hmm how so?
20:01:07  <Bakkot>it could have a branch for when Symbol.asyncIterator is present on its argument which did the logic you wanted there
20:01:17  <Bakkot>disclaimer: have not thought about this for more than five seconds
20:01:26  <zenparsing>an "itertools" standard lib of some is needed for different iterator operations. I was hopeful that it could be an std module.
20:02:00  <zenparsing>(of some kind)
20:02:14  <Domenic>Bakkot: ah interesting, I'm not sure I'd want to overload `Promise.all()` in that way, but it vaguely rhymes.
20:02:18  <Bakkot>that is, I am proposing that `Promise.all(asyncIterator)` could be an overload which would return a promise for an array, the same way `Promise.all(syncIterator)` currently does
20:02:37  <Domenic>I guess the return types are indeed the same.
20:03:14  <littledan>zenparsing: +1
20:03:15  <Domenic>zenparsing: I feel like `[Async]Iterator.prototype` is underused, personally.
20:03:34  <littledan>zenparsing: I've been hoping that for a while. I'm excited to see built-in modules moving along
20:03:49  <Domenic>We went to all the trouble to wire it up, if we're going to add iterator utilities anywhere, it should be there, IMO.
20:03:58  <littledan>there have been various proposals to use Iterator.prototype, but they haven't moved along. Does anyone know whether there were real objections to using it?
20:04:22  <Domenic>I think it's just complicated.
20:05:01  <Domenic>Especially if you want to do the proper thing where `iterator.filter(...).map(...).reduce(...)` only does one iteration in total.
20:05:04  <Bakkot>IIRC the main problem was lack of a broadly agreed upon vision of where things belong - stdlib, on the containers themselves, on the container-specific iterators, on the iterator prototype
20:05:38  <Domenic>Containers themselves always need some methods; it's more ergonomic than going container -> generic iterator stuff -> back to container. I do remember that discussion.
20:06:00  * mgoljoined
20:06:04  <Domenic>But between itertools functions and Iterator.prototype methods, I'm not sure we really had that discussion.
20:07:14  <zenparsing>one advantage of itertools is that I don't have to subclass Iterator for users to get the goodies
20:07:48  <zenparsing>(or require them to do Iterator.from or somesuch)
20:07:58  <Bakkot>+1
20:09:23  <Domenic>Who is writing custom iterators?
20:09:43  <Domenic>If people are doing that, I agree it sucks today, because we for some reason didn't make Iterator global.
20:09:50  <Bakkot>generators? though I forget how that prototype chain works
20:09:59  <Domenic>Nah those inherit
20:10:11  <devsnek>i really want a global iterator object
20:10:15  <devsnek>like Math
20:10:33  <Domenic>https://chromium-review.googlesource.com/c/chromium/src/+/1396453/3/third_party/blink/renderer/core/script/resources/layered_api/kv-storage/async_iterator.js#13 is pretty ridiculous, but as long as it's only platform code having to do it, I'm not too mad.
20:10:59  <devsnek>and i want Iterator.prototype and Iterator.asyncPrototype
20:11:50  <Domenic>Oh right, there is no actual Iterator constructor, so it'd have to be a namespace.
20:11:54  <devsnek>yeah like Math
20:12:02  <devsnek>i had a gist somewhere
20:12:17  <devsnek>here we go https://gist.github.com/devsnek/230919934eff442a31f9e3116a752c68
20:12:55  <Domenic>Those are nice but they miss doing the proper thing where `iterator.filter(...).map(...).reduce(...)` only does one iteration in total.
20:13:11  <devsnek>huh
20:13:17  <devsnek>they each return another iterator
20:13:25  <devsnek>except for collect
20:13:45  <devsnek>the last `.next()` would turn each item in the chain once
20:13:48  <Domenic>Hmm you may be right
20:13:53  <Bakkot>what do you mean by "only does one iteration total"?
20:14:03  <devsnek>like the chain should be lazy
20:14:04  <Bakkot>it looks like they would work for an iterator which could only be iterated once
20:14:23  <Domenic>I remember reading an implementation of C# LINQ that did something of that sort and I remember it being complicated. So I assumed something simple like that would not be enough.
20:14:37  <devsnek>everything is simple in js :)
20:14:38  <Domenic>I am now going to re-read that C# thing to see if maybe it was simpler than I thought.
20:14:46  <devsnek>link the c# thing
20:15:08  <Bakkot>also I recall seeing a library somewhere which provided similar utils, but have lost the link
20:15:15  <devsnek>itertools
20:15:29  <devsnek>https://www.npmjs.com/package/itertools
20:15:37  <devsnek>itertools is more focused on array-likes though
20:15:48  <devsnek>since it existed before the iterator protocol
20:16:07  <Domenic>Ah no it's fine
20:16:10  <Domenic>It's complicated for LINQ to SQL
20:16:20  <devsnek>lol
20:16:23  <Domenic>But it's simple for LINQ to objects (which is what we're discussing)
20:16:29  <littledan><small>the pipeline operator might make itertools as a module more attractive</small>
20:16:42  <devsnek>if we get pipeline or call bind synax
20:16:52  <devsnek>Iterator.map and such would be cool
20:16:55  <Domenic>LINQ to SQL needs to basically build up a graph of operations as you call them and then at the serialization-to-SQL step convert it into a SQL query. Which involves lots of intermediate state tracking.
20:16:57  <devsnek>or on the prototype
20:17:02  <devsnek>bind syntax is a weird feature
20:17:14  <Domenic>Yeah putting them on the prototype allows us to put off the pipeline operator longer ;)
20:17:18  <devsnek>lol
20:17:21  <Bakkot>prototype definitely seems like the right place for most of these, if possible
20:17:31  <devsnek>but the lodash users will be angry
20:18:00  <Domenic>https://gist.github.com/devsnek/230919934eff442a31f9e3116a752c68 seems like a good start, someone should champion that.
20:18:17  <Domenic>devsnek do you have time to write a formal spec if I do the committee presentation work?
20:18:23  <devsnek>sure
20:18:38  <littledan>(I think the pipeline operator is justified even if we don't have anything in the standard library that's defined for it)
20:18:41  <devsnek>if i get that internship i could even present it myself 🤷‍♂️
20:18:47  <Domenic>Indeed!
20:19:14  <Domenic>Well, when you have a repo that you feel is stage 1 worthy (i.e. a nice README) let me know and I'll put something on the agenda of whatever meeting is next.
20:19:23  <devsnek>i'll put it on my todo list
20:19:30  <devsnek>well its been on my todo list
20:19:32  <zenparsing>littledan: the nice thing about "elixer-style" (first arg passing) is that you don't need to write a lib specifically for it
20:19:44  <devsnek>but writing iterator stuff without generator syntax is annoying and i keep putting it off
20:20:10  <Domenic>Yeah... the formal spec will be annoying
20:20:16  <devsnek>if we can write "let x be Await(y)" why can't we write "let x be Yield(y)"
20:20:19  <Domenic>The readme won't be too bad.
20:20:29  <littledan>zenparsing: Right (to some extent--there's definitely already code written in a currying style that would work out of the box with F#)
20:20:44  <Domenic>We might be able to introduce a Yield() macro, although every time I use the Await() macro I confuse myself, so :-/.
20:21:35  <littledan>probably starting with a README with good docs and a polyfill would be good... we can compile it into spec text later
20:22:55  <devsnek>is a proposal without a champion a 0 or a -1
20:23:11  <devsnek>0 right
20:23:19  <Domenic>0 is whatever you want it to be
20:23:27  <Domenic>0 has no rules
20:23:48  <devsnek>how about -0
20:26:11  <Bakkot>re: an overload for Promise.all, it occurs to me that this might be a problem if anyone ever defines both Symbol.iterator and Symbol.asyncIterator, which guess I could conceive of. also couldn't obviously be extended to `Promise.race` or even `Promise.allSettled` I don't think.
20:26:26  <Bakkot>I still like Promise.all as the place for that operation though.
20:26:53  <devsnek>if you use both it just depends on the consumer
20:27:23  <devsnek>GetIterator() with hint=async would try to grab asyncIterator first the fall back to AsyncFromSyncIterator
20:27:56  <Bakkot>Promise.all should not fall back to AsyncFromSyncIterator
20:28:03  <Bakkot>but yeah, it could be spec'd
20:28:17  <Bakkot>I'm just concerned about surprise, especially because it could change the semantics of existing code
20:28:18  <Domenic>Hmmm but if it did would the behavior be equivalent? If so that would be a powerful hint that this is really one unified operation.
20:28:25  <Domenic>I mean I guess the answer is yes.
20:29:08  <Bakkot>hm, yeah, I guess Promise.all's early throwing makes that work
20:30:04  <devsnek>why couldn't it using normal iterator handling
20:30:15  <devsnek>that would make it easy to also include the existing behaviour of taking an array
20:30:29  <Domenic>We would branch and fall back to existing behavior, for speed/observability if nothing else
20:30:29  <Bakkot>I do not understand the question
20:30:57  <Domenic>But it's nice to know that if we defined Promise.all() as operating primarily on async iterators, with async-from-sync-iterator fallback, it would behave basically the same as today's Promise.all()
20:31:18  <Domenic>(Probably with like 3x as many .then() accesses and intermediate objects being the difference.)
20:31:22  <devsnek>lol
20:31:40  <devsnek>you can just JIT all that away right :P
20:43:30  <littledan>turns out you can't just JIT everything away
20:43:52  <littledan>optimizing everything when it's subclassable ends up leading to some pretty bad performance cliffs
20:45:10  <littledan>or, depending how you cut it, maybe it'll work sometimes, and still unreliably, and only after the program was running for a while. But turns out that a lot of the execution time is the first time, or the first few times
20:46:39  <littledan>Promise.all has improved a bunch in V8, but the most thorough way to do these things is to reserve for the situations where it's really really useful the design of everything being subclassable and having the methods in the subclasses be invoked
20:47:04  <littledan>remember, we just made a change to async/await which was all about removing an intermediate Promise ("shouldn't the JIT be able to eliminate it?")
20:56:25  <Domenic>Indeed, I'd hoped we learned our lesson about over-genericism and subclassability, but all the recent discussions on `Set` methods makes me think we have not :(
21:04:15  * nomadtechie_joined
21:04:37  * rkirsling_joined
21:04:49  * zenparsing_joined
21:04:54  * samth_joined
21:06:32  <littledan>yep :(
21:07:28  <Bakkot>Domenic: for the set methods the generality is generally restricted to places where it won't hurt performance for the common case, which I think is the right approach
21:07:48  <Bakkot>with the exception of using Symbol.species, I guess
21:07:56  * annevk_joined
21:08:34  * ystartsev_joined
21:09:24  <Domenic>It's hurting the complexity of the methods' mental models, regardless as to whether they're theoretically common-case optimizable.
21:11:38  * rkirslingquit (Ping timeout: 268 seconds)
21:11:39  * annevkquit (Ping timeout: 268 seconds)
21:11:39  * nomadtechiequit (Ping timeout: 268 seconds)
21:11:43  * saulh[m]quit (Ping timeout: 268 seconds)
21:11:43  * ystartsevquit (Ping timeout: 268 seconds)
21:11:43  * samthquit (Ping timeout: 268 seconds)
21:11:45  * zenparsingquit (Ping timeout: 268 seconds)
21:11:45  * rkirsling_changed nick to rkirsling
21:11:45  * annevk_changed nick to annevk
21:11:45  * samth_changed nick to samth
21:11:45  * ystartsev_changed nick to ystartsev
21:12:06  <Bakkot>I have the exact opposite intuition, I guess
21:12:17  <Bakkot>well, making isSubsetOf take an iterable hurts the complexity of its mental model, I suppose
21:13:18  * saulh[m]joined
21:13:33  <Bakkot>otherwise my mental model is "isSubsetOf needs to iterate its receiver and query membership in its argument, isSupersetOf needs to iterate its argument and query membership in its receiver", etc, and want all the methods to do those things in ways consistent with each other and without big-O cliffs for well-behaved subclasses
21:26:01  <devsnek>Domenic: threw this together during lunch https://github.com/devsnek/proposal-iterator-helpers
21:26:29  <Domenic>My intuition is that the simple thing is that set methods operate on Sets using SetData
21:26:54  <ljharb>Domenic: would your intuition be harmed if, lacking SetData, it constructed a Set on which to operate?
21:27:00  <Domenic>Yeah
21:27:21  <Domenic>Just take Sets. If it's not a Set, then TypeError, oh well.
21:27:25  <ljharb>so you'd prefer the explicit `set.someOp(new Set(iterable))`
21:27:31  <Domenic>Indeed.
21:28:32  <Domenic>devsnek: this is pretty solid, hmm. Maybe I'll dial in to try to present this at the next meeting.
21:29:17  <Bakkot>Domenic: funnily enough, the argument against that was that the explicit pattern would be too hard to optimize
21:31:16  * keith_millerquit (Quit: My MacBook has gone to sleep. ZZZzzz…)
21:32:54  * zenparsing_quit
21:33:14  * zenparsing_joined
21:33:55  * zenparsing_quit (Client Quit)
21:34:38  * zenparsingjoined
21:48:24  <Domenic>devsnek: https://github.com/tc39/agendas/commit/081bcf2b63d01bc60688ca2b9c860db9bb361c4f
21:57:51  <devsnek>woo
21:58:15  <gsathya>Bakkot, not too hard to optimize, but *harder* to optimize for the baseline
21:58:53  <TabAtkins>I'm not in favor of the "explicit pattern". I do enough work with Sets in Python that I already have my fingers trained to use the methods rather than the operators, specifically because the methods will convert iterables while the operators strictly require both args to be sets.
22:00:06  <TabAtkins>Like, use SetData if you receive a Set, sure, but allow iterables too, as its' good for ergonomics. I don't think the extra `new Set(...)` adds any meaningful safety or readability signals to the code.
22:00:54  <TabAtkins>(It also means that I'll naturally want to instead provide a wrapper function that either returns its arg if it's a Set or constructs a Set from it, so I'm not causing extra object churn for no reason.)
22:01:30  * keith_millerjoined
22:03:23  <Bakkot>If you're going to accept an iterable, though, you do need to short-circuit once you have enough to answer your question, like `.every` etc
22:04:15  <ljharb>not necessarily - if you constructed a set with it, you'd exhaust the iterable first, and then operate on SetData
22:04:21  <Bakkot>right, and that would be wrong
22:04:31  <Bakkot>that is, the wrong thing for a method accepting an iterable to do
22:04:48  <ljharb>that's what Array.from does?
22:05:07  <Bakkot>Array.from can't short-circuit, surely?
22:05:11  <ljharb>oh sure, that's true
22:05:17  <ljharb>but short-circuiting is an implementation detail
22:05:30  <Bakkot>no, it's not
22:05:39  <Bakkot>it critically affects performance in many cases
22:05:43  <ljharb>like it's true that `.some` short circuits, but conceptually it's answering the question "do any of these items pass the predicate"
22:07:18  <Bakkot>yeah, but if it answered that question without short-circuiting, I would never use it or allow it to be used in codebases I maintained
22:07:53  <ljharb>sure, but that's not the same thing as it being an intrinsic part of the conceptual operation
22:09:14  <gsathya>given no monkey patching, the engine can just do this, right? why do we need to spec this early bailout?
22:09:50  <ljharb>well, if we specced it like "construct a set from the iterable", it'd have to exhaust it, i think
22:09:55  <Bakkot>lacking a definition for "intrinsic part of the conceptual operation", I can't really disagree, but I would be very surprised by the non-short-circuiting behavior
22:10:00  <ljharb>noted
22:10:21  <Bakkot>ljharb: if the engine can observe the no-monkey-patching, it can skip the whole affair and do whatever it wants, including early bailout
22:10:24  <gsathya>ljharb, why?
22:10:25  <gsathya>yeah
22:10:32  <gsathya>what Bakkot said
22:10:40  <ljharb>ohhhh right
22:10:47  <ljharb>wait
22:11:00  <Bakkot>gsathya: that is true in the case that you pass an array, but it should still be required to do the right thing if you pass it a more complicated iterable
22:11:03  <ljharb>if it's internally specced to do `new Set(iterable)`, then there's no bailout possible
22:11:22  <ljharb>for a non-monkeypatched array, or a Set, sure, but not for a generator
22:11:37  <Bakkot>right, gsathya was talking specifically about the case of passing a non-monkeypatched array, I am pretty sure
22:11:51  <Bakkot>(else I am also confused)
22:11:59  <Bakkot>(sorry, I should let him speak for himself)
22:12:15  <gsathya>yes, non monkey patched array is the common case (.. and that's what I care about the most)
22:12:20  <gsathya>I don't think it's worthwhile to complicate the spec for making some very narrow use case slightly faster
22:12:39  <ljharb>i mean, no matter what we're likely to do, "sets" and "non monkeypatched arrays" can be made to be fast, i assume
22:14:10  <Bakkot>there's a lot of non-array iterables around, and short-circuiting is not just "slightly" faster in many cases
22:14:52  <gsathya>if you have a non array iterable, then your perf is already shot
22:15:43  <Bakkot>"hits slower path" is a very different kind of perf being shot than "takes 1000 steps when 1 would have done"
22:15:57  <ljharb>gsathya: strings?
22:17:24  <gsathya>ljharb, sure we can optimize that too; built in iterables can be optimized
22:17:53  <gsathya>it's just the user defined ones that need to go through the whole iteration protocol dance
22:18:03  <ljharb>gotcha
22:20:01  <gsathya>Bakkot, not sure I agree but I don't have any data
22:21:51  <Bakkot>I don't think data can answer this one? because in the cases engines can't optimize it would be, specifically, taking 1 step on the slow path vs taking 1000 steps on the slow path
22:22:30  <gsathya>err, I meant generally comparing "hits slower path"
22:22:47  <gsathya>if in general, "hits slower path" is going to dominate perf then this is a non issue
22:23:47  <Bakkot>ah, understand
22:25:57  <Bakkot>I dunno; I would guess that there's a lot of code which hits slow paths which still ends up perfectly reasonable in practice, but which would not if some operation on the critical path was an order of magnitude slower
22:26:21  <Bakkot>that is to say, I think it's still worth caring about performance implications for code which hits slow paths, esp. when the slow path is as wide as "any user-defined iterable"
22:31:03  <gsathya>I definitely agree that we should care about the slow paths (which is exactly why I'm focusing on the Array as an iterable case) but if you want everything to be fast, then nothing is
22:32:04  <gsathya>(the fast path is when the argument is a Set, the rest are all slow-er paths)
22:35:25  <Bakkot>If there's a reason specing the short-circuiting would actually slow down cases which the engine would otherwise have been able to optimize, that might be a good reason to give it up, but it doesn't seem like there ought to be?
22:43:35  <gsathya>I think there's a lot of value in keeping the spec simple, especially when implementations try to optimize this. At this point, I don't think your changes will cause any of the optimizations I can think of to go away
22:44:47  <gsathya>it blows my mind that a trivial isSubsetOf is going to be a page long spec
22:45:11  <TabAtkins>Ain't nothing's trivial when everything's observable. ^_^
22:45:33  <TabAtkins>(And when all observable aspects become depended-upon parts of the API contract.)
22:46:43  <gsathya>good thing I'm giving up on all my proposals after this
22:48:10  <TabAtkins>hahaha
22:55:50  * AtumTquit (Quit: AtumT)
23:02:55  <devsnek>python lets you tee iterators 😓
23:04:26  * mgolquit (Ping timeout: 244 seconds)
23:11:06  * keith_millerquit (Quit: My MacBook has gone to sleep. ZZZzzz…)
23:19:05  * keith_millerjoined
23:22:49  * mgoljoined
23:25:05  * keith_millerquit (Quit: My MacBook has gone to sleep. ZZZzzz…)
23:53:41  * mgolquit (Quit: My MacBook has gone to sleep. ZZZzzz…)