00:01
<TabAtkins>
`let value = do { let t; for(const v of values) { if(pred(v)) { t=v; break; } }; t}`
00:01
<devsnek>
i don't hate having to do that
00:01
<devsnek>
but i much prefer using the completion value
00:01
<TabAtkins>
vs `let value = do { for(const v of values) if(pred(v)) break with v; };`
00:02
<devsnek>
actually break with and continue with are good ideas
00:02
<ljharb>
oof
00:02
<devsnek>
no no wait
00:03
<devsnek>
loops complete with undefined unless you use `break with`
00:03
<devsnek>
continue with makes no sense pretend i didn't say that
00:03
<ljharb>
`break with` is at least explicit
00:04
<devsnek>
seems we have options
00:04
<Bakkot>
options are kind of the problem because we don't have a good way to choose between them
00:04
<devsnek>
options which aren't blocking each other
00:05
<Bakkot>
I am hoping there is a minimal subset which just bans everything people disagree about and is still useful for some cases
00:05
<rkirsling>
is there a demand for `return` to refer to the function scope though?
00:05
<devsnek>
yes
00:05
<devsnek>
that's my primary use case
00:05
<rkirsling>
oh.
00:06
<devsnek>
lol
00:06
<ljharb>
it would be exceedingly confusing for `return` to not mean that imo
00:07
<devsnek>
to me it just seems
00:07
<devsnek>
you have some logic
00:07
<rkirsling>
depends on how you're conceiving of this magical statement-to-expression space
00:07
<devsnek>
you refactor it to use a do expression
00:08
<devsnek>
now all of a sudden you have to restructure your control flow
00:08
<devsnek>
because you can use break/continue/return inside it
00:08
<devsnek>
can't*
00:08
<rkirsling>
hmm that's not a bad point
00:09
<rkirsling>
ugh the further this discussion goes on though, the more unsure I become about the feature
00:09
<rkirsling>
like, I love "everything's an expression" but
00:10
<rkirsling>
does that imply that I actually have a convincing use case for "a block that turns all your imperative logic into an expression when all is said and done"?
00:10
<devsnek>
i would use it all over the place to structure things
00:11
<devsnek>
it's like the big brother of empty lines between things
00:11
<rkirsling>
as like, local functions without call overhead?
00:11
<devsnek>
i mean like
00:12
<devsnek>
when you have a bunch of lines of code, you generally group them with empty lines
00:12
<devsnek>
often in rust people also scope them using block expressions
00:12
<devsnek>
and i really like that pattern
00:12
<rkirsling>
wait what why
00:12
<rkirsling>
why waste syntax if it's no better than newlines
00:13
<rkirsling>
oh ,you're saying like
00:13
<devsnek>
irc needs multiline support
00:13
<rkirsling>
"there's no need for this to go out of scope yet but doing so clarifies the fact that I'm only using it *right here*"
00:14
<devsnek>
yeah
00:14
<devsnek>
its just clean
00:14
<devsnek>
you end up at the end with just the variables you're actually using
00:14
<rkirsling>
and then said "paragraph" or "stanza" or whatever you wanna call it _has_ a result
00:14
<devsnek>
oh eah
00:14
<devsnek>
yeah
00:14
<devsnek>
they produce results
00:14
<rkirsling>
so that'd give the block purpose in Rust
00:14
<rkirsling>
but in JS we'd need a new thing
00:14
<rkirsling>
okay
00:15
<devsnek>
yeah in rust you can do `let x = { 5 };`
00:15
<rkirsling>
that is, while abstract, not unconvincing
00:15
<rkirsling>
right
00:15
<devsnek>
rust has way better semantics around that though
00:15
<rkirsling>
so then even like
00:16
<devsnek>
https://gc.gy/57811604.png
00:17
<rkirsling>
const result = do {
00:17
<rkirsling>
const myNamedBoolArg = true;
00:17
<rkirsling>
foo(data, myNamedBoolArg);
00:17
<rkirsling>
};
00:17
<devsnek>
yeah you could do that
00:18
<rkirsling>
kinda superfluous but yeah, documents itself, perhaps
00:19
<devsnek>
honestly the most op pattern is if expressions
00:19
<devsnek>
we could replace do expressions with `if (true) {}` if expressions :P
00:19
<rkirsling>
I kind of resent Rust's lack of ternary but yeah, if you have any nontrivial branches then if exprs are pretty darn great
00:20
<rkirsling>
lol
00:23
<Bakkot>
anyway so: does anyone here _object_ to, do expressions, where you cannot have your last statement be a loop or declaration, and break/return/continue are banned?
00:23
<Bakkot>
I know this does not meet devsnek's use case
00:24
<Bakkot>
but hope that it is useful enough anyway
00:24
<devsnek>
if I represented myself I would object
00:25
<Bakkot>
on what basis?
00:25
<devsnek>
on not having control flow
00:26
<Bakkot>
I know it doesn't meet your use case; is your position that it is not worth having if it does not meet your use case?
00:26
<devsnek>
I'm imagining a lot of humans would want to use it
00:26
<Bakkot>
it's not like adding this without allowing break/return prevents relaxing that restriction later
00:26
<devsnek>
given my refactoring point above
00:26
<devsnek>
so I'm worried it wouldn't be useful enough without control flow
00:27
<Bakkot>
I personally would still find it very useful
00:27
<devsnek>
maybe someone with a zillion followers on twitter can make a poll
00:28
<rkirsling>
I think it's worth presenting
00:28
<Bakkot>
I think most of the pipeline proposal's use cases would be met by this, also
00:28
<rkirsling>
oh god not a Twitter poll
00:28
<devsnek>
seems useful for pipeline yeah
00:28
<Bakkot>
also to do `let x = try { foo() } catch { null }` which is very common
00:28
<Bakkot>
ime
00:29
<devsnek>
if we get do expressions do we drop the throw expression proposal
00:29
<rkirsling>
tbh if we go back to the pipeline discussion though and the refactorings TabAtkins was showing above, I really do think the `#`-chasing leads to comprehensibility
00:30
<devsnek>
if the spec requires the hash to be bright red when displayed
00:30
<rkirsling>
:stare:
00:30
<devsnek>
Bakkot: I'd feel better about it if pipelines advance
00:31
<Bakkot>
devsnek: ... why?
00:31
<devsnek>
but like I said I don't think I'll actually block either way
00:31
<Bakkot>
I'm mostly interested in this as an _alternative_ to pipelines
00:31
<devsnek>
because people won't use control flow in them
00:31
<devsnek>
oh interesting
00:32
<devsnek>
yeah I guess that was mentioned above
00:32
<Bakkot>
like instead of `x = a |> b(0, #) |> await #` ro whatever, you'd write `x = do { let $=a; $=b(0, #); await #}`
00:32
<Bakkot>
s/ro whatever/or whatever/
00:32
<Bakkot>
also s/#/$/g
00:32
<rkirsling>
but I kinda thought avoiding locals was the point
00:32
<devsnek>
are there real world examples of that
00:33
<devsnek>
HOC with await or something
00:33
<rkirsling>
(not the point of the proposal but the reason why existing approaches don't suffice, I mean)
00:34
<Bakkot>
rkirsling I think the main reason for avoiding locals is so that you can remain in expression position, and also not pollute your local scope
00:34
<Bakkot>
some people (pointfree people) have a principled objection to locals, but I don't think that's the dominant party
00:34
<rkirsling>
hmm okay
00:34
<rkirsling>
I do see your point
00:39
<Bakkot>
devsnek: `console.log(filter(parse(await fetch(extractRemoteUrl(await readDB(makeQuery('some query'))))));` is the sort of thing I write a lot
00:39
<Bakkot>
well, obviously I break it up into multiple lines with locals
00:39
<Bakkot>
but you get the idea
00:39
<Bakkot>
not HOCs or whatever
00:39
<Bakkot>
just normal chasing data around
00:40
<devsnek>
is that code real
00:40
<TabAtkins>
it looks *plausible*, at least
00:40
<TabAtkins>
I've written code like that ^_^
00:40
<devsnek>
I've never seen code like that
00:40
<devsnek>
I don't think
00:40
<Bakkot>
it is not literally copied from one of the proprietary code bases I work on, no
00:41
<devsnek>
if things like it exist I'll believe you
00:41
<Bakkot>
but it is very much the sort of thing I write in them, except I would make intermediate variables so a human could read it
00:41
<TabAtkins>
my python instincts these days would probably force me to break that up into multiple assignments, but still
00:42
<devsnek>
I just have never seen them so i would like to get a sense of what real world code looks like
00:50
<rkirsling>
agree that it looks plausible
00:50
<shu>
Bakkot: are you taking up do expressions again
00:50
<rkirsling>
(regardless of whether it'd get past code review, tehe)
00:52
<Bakkot>
shu: maybe
00:52
<shu>
okay
00:52
<Bakkot>
shu: mostly I would like them discussed if we talk about pipelines again
00:52
<shu>
i do not think pipelines are a good idea currently
00:52
<Bakkot>
because I think they are better than pipelines and also mean you don't need pipelines
00:52
<shu>
great
00:57
<devsnek>
shu: what do you think about control flow in do expressions
00:58
<shu>
control flow that breaks out of do expressions?
00:58
<shu>
like a return in a do expression?
00:58
<devsnek>
yeah
00:59
<devsnek>
return returns the outer function that is
01:00
<shu>
that seems like a bad idea
01:00
<devsnek>
:(
01:00
<shu>
what's the motivation for having that behavior?
01:02
<shu>
oh i see some backlog, you're worried about a refactoring hazard?
01:02
<devsnek>
yeah
01:02
<devsnek>
i mean i also have a use case for returning in them
01:02
<devsnek>
but more generally the refactoring hazard seems annoying
01:03
<devsnek>
i can imagine code like `let x; try { x = z() } catch { break }` exists
01:03
<devsnek>
or similar with if/else
01:03
<shu>
my opinion is those patterns are more harm than good
01:04
<shu>
those patterns = to expect to wrap them in an expression and keep the same behavior
01:04
<devsnek>
yeah i mean
01:04
<devsnek>
adding a block around code doesn't change control flow
01:05
<devsnek>
i don't get why adding `let x = do` at the front of the block is so controversial
01:05
<shu>
why is that comparable here?
01:05
<devsnek>
aside from the break inside while loop head
01:05
<devsnek>
i get why that is weird
01:05
<devsnek>
s/while loop/loop/
01:06
<shu>
because in an algol-like language there are certain (fairly strong imo) properties that tend to hold of statements and expressions
01:06
<shu>
and one of them is generally that expressions evaluate beginning to end without affecting the control flow of the surrounding context, whatever that is
01:06
<devsnek>
i've never used algol
01:06
<shu>
sometimes you have exceptions that aren't too confusing
01:07
<shu>
well, c-like then
01:07
<devsnek>
i guess
01:07
<devsnek>
i don't see any strong reason to have a separation
01:07
<shu>
dunno what to tell ya
01:07
<shu>
most people i think do
01:07
<devsnek>
like some things obviously don't make sense as expressions
01:08
<devsnek>
like variable declarations
01:08
<devsnek>
what property do you get from strong separation of expressions and control flow
01:09
<shu>
the property of not having to think about control flow if i'm reading an expression position
01:09
<shu>
anywho gotta run
01:09
<devsnek>
aight
01:11
<shu>
fwiw i think the property i like is a little stronger than the expression/statement split, it's more about having clear scopes where control flow has effect
01:11
<shu>
e.g. break doesn't work in expression contexts now, to suddenly make it work is a very big ask
01:11
<rkirsling>
I can agree insofar as control flow _within_ seems okay, it's control flow _through_ that gives pause
01:11
<shu>
right
01:12
<shu>
put another way, control flow in JS is delimited in certain ways today
01:12
<shu>
to change that is a *huge* ask and break in mental model that i'd fight against
01:12
<shu>
in languages with undelimited continuations, that shit is hard to wrap your head around for similar reasons
01:12
<devsnek>
i don't quite understand what that mental model is
01:12
<shu>
and why people end up using delimited continuations
01:12
<devsnek>
maybe i'll read some algol stuff
01:13
<shu>
i don't know if algol is a good starting point
01:13
<devsnek>
i just really don't understand the separation of statements and expressions
01:14
<shu>
but i'm pretty sure you have a mental model of what return does, right? the mental experiment i recommend is 1) ask if you also think presence of call/cc or setjmp/longjmp make reasoning about return hard, and 2) if you find the difficulty comparable, but to a lesser degree, with allowing returns in expressions
01:15
<devsnek>
what is cc
01:15
<Bakkot>
https://en.wikipedia.org/wiki/Call-with-current-continuation
01:15
<Bakkot>
one of the other major paradigms for control flow
01:16
<shu>
that's probably not a good example, return-in-expressions aren't undelimited
01:16
<devsnek>
well i will say
01:16
<shu>
look at shift/reset instead
01:16
<devsnek>
reasoning about longjmp is very difficult
01:20
<rkirsling>
is it funny that I know about call/cc but am having to look up longjmp
01:21
<rkirsling>
(I mean it's sort of what I was expecting but still)
01:22
<devsnek>
i knew about longjmp but not call/cc
01:22
<devsnek>
call/cc is weird
01:22
<devsnek>
i find call/cc and longjmp to be a completely different universe of complexity compared to returning from inside a do expression
01:23
<Bakkot>
call/cc is yield on steroids, basically
01:23
<devsnek>
idk why all the websites have to make it sound so complex
01:23
<devsnek>
well i mean it is complex
01:24
<devsnek>
but i feel like these concepts are always explained in the most difficult terms instead of the easiest terms
01:24
<devsnek>
in any case, call/cc and longjmp are both dynamic
01:25
<devsnek>
and involve non-local control flow
01:25
<devsnek>
i don't really see a comparison between them and allowing break/return/continue inside do expressions
01:30
<rkirsling>
hah, good old Oleg
01:30
<rkirsling>
https://en.wikipedia.org/wiki/Call-with-current-continuation#Criticism
01:30
<devsnek>
call/cc makes sense if you don't use the word "continuation"
01:31
<devsnek>
its like when people explain monads
01:40
<rkirsling>
I usually just think of "continuation" just as "return target" but then it makes "current continuation" a bit more confusing
01:41
<devsnek>
i posted the block-expression control flow vs call/cc thing in a programming language design discord
01:42
<devsnek>
people are angry that they would be equated
01:50
<shu>
i did not equate them
01:51
<devsnek>
i don't understand what the comparison is
01:52
<shu>
the point was a broad one: you have expectations when reading "return" of what it does, and those expectations must be thrown out when you see setjmp/longjmp
01:52
<shu>
similarly, to a lesser degree, people's expectations of "return" will need to be re-calibrated if they are allowed in do expressions in JS
01:53
<devsnek>
aside from "i don't expect there to be a return value in this syntactic position (because that's true of any statement)" what is the expectation there
01:53
<shu>
as i said before, that expressions do not affect control flow
01:53
<rkirsling>
(wow I forgot that you can't throw from a ternary in JS)
01:54
<devsnek>
throw expressions is a proposal
01:54
<devsnek>
shu: out of curiosity have you used any languages with this feature before
01:54
<devsnek>
like rust or smth
01:55
<shu>
i have used rust, but an earlier version and not since 1.0 i don't think
01:55
<rkirsling>
like I was saying though, I think it's very different when "everything is a statement"
01:55
<rkirsling>
dammit
01:55
<rkirsling>
s/statement/expression/
01:55
<devsnek>
also i'm curious about if yield and await violate your expectations
01:55
<rkirsling>
like, the thing that creates confusion or weird expectations is the do block
01:56
<rkirsling>
we have this barrier between worlds and it's tricky to decide upon its properties
01:56
<rkirsling>
if there's no barrier, there's nothing to be confused about
01:56
<devsnek>
i just don't understand this expectation or why maintaining it matters
01:57
<devsnek>
i don't think i've ever seen a rust user be confused about it anyway
01:57
<devsnek>
maybe that's because they're too busy being confused about lifetimes
01:57
<rkirsling>
there's nothing _to be confused about_ in Rust
01:57
<devsnek>
wdym
01:58
<rkirsling>
`do { ... }` raises the question of "just how much is this thing like a function scope"
01:58
<devsnek>
i don't understand why it does
01:58
<devsnek>
https://www.irccloud.com/pastebin/aJYvqDl4/x.rs
01:58
<devsnek>
so here's an example from rust
01:59
<shu>
devsnek: yield and await do not violate my expectations, since they produce values usable as expressions
01:59
<devsnek>
they don't have to
01:59
<devsnek>
they might never return
01:59
<rkirsling>
devsnek: if you shorten it to that extent then it could go either way though
01:59
<shu>
devsnek: right?
02:00
<devsnek>
how is that control flow different
02:00
<shu>
than return and break, which transfer control and do not return a value?
02:00
<devsnek>
yield and await both transfer control
02:00
<shu>
yield and return abstract their control flow in such a way that should execution resume, you're back at where you were, with a new value (that you may use or not)
02:01
<devsnek>
and might not return a value
02:01
<shu>
err
02:01
<shu>
yield and await
02:02
<devsnek>
shu: what if i told you return could resume but it never does
02:02
<shu>
i don't understand what that means
02:02
<bradleymeck>
it would still fire the finally around it though?
02:02
<devsnek>
why does being able to resume change the control-flow-ness of an operator
02:02
<bradleymeck>
try { return } finally { ... }
02:03
<devsnek>
bradleymeck: talking about whether control flow should be allowed in do expressions btw
02:03
<bradleymeck>
i think its just a mental model of the control flow being a valid expression itself
02:03
<bradleymeck>
foo(return) doesn't make any sense, and that gets confusing in foo(do { return })
02:04
<devsnek>
if return parsed as an expression it could make sense
02:05
<bradleymeck>
it could parse in the same position but it would never have a value generated for that position
02:05
<devsnek>
right its a never type
02:05
<bradleymeck>
i don't actually care about such a thought myself, but it seems to come up
02:05
<devsnek>
same as a function that always throws
02:06
<bradleymeck>
but thats in a different "frame/scope", so often not thought of when reading the code (even if it is a valid point)
02:07
<shu>
devsnek: i feel like you are not receptive to what i have said, and that's okay. you asked what i thought of control flow in do expressions
02:07
<devsnek>
shu: no i just want to understand
02:07
<bradleymeck>
i think control flow in do expressions is fine-ish, finally {} can get confusing if you cancel ending the frame
02:07
<devsnek>
sorry if that didn't come across well
02:08
<devsnek>
finally is a good point about how people can understand odd control flow
02:08
<shu>
it seems like you don't have any different expectations of expressions and statements wrt control flow
02:08
<shu>
i do
02:09
<shu>
the existence of odd control flow in the language now doesn't have generalize to "therefore allowing them in expressions doesn't change expectations"
02:09
<bradleymeck>
my only concern is from half finished statements: `while(...) { foo(sideEffect, do {continue}); }` currently statements are the points to observe non-throw control flow
02:09
<devsnek>
if that's all it comes down to i would say keeping that expectation doesn't matter that much
02:09
<bradleymeck>
so, you have to walk expressions for throws but not for other things
02:10
<shu>
await being an expression because it needs to return a value did require some extra restrictions
02:10
<shu>
like disallowing it in parameter expressions
02:10
<shu>
devsnek: that's an opinion, not an argument?
02:14
<devsnek>
shu: right i meant, there's no point in trying to draw a conclusive decision from just an opinion
02:14
<shu>
who... is trying to do that?
02:15
<devsnek>
well i was trying to do that
02:15
<devsnek>
until you clarified
02:15
<devsnek>
i was trying to get to a point where i could make a decision based on what you were saying
02:17
<shu>
i missed that context, thought you just wanted my thoughts. a decision on?
02:18
<devsnek>
i was trying to figure out the importance of control flow in do expressions
02:18
<devsnek>
or lackthereof
02:19
<shu>
it seemed like your own opinion is pretty strong already, that they should be allowed
02:20
<bradleymeck>
i'd be equally curious of why we couldn't enable control flow later. though i bet in general just banning them directly inside of params wouldn't be terrible
02:25
<devsnek>
you don't really have to explicitly ban them inside params or anything
02:26
<devsnek>
like theoretically loop heads and function params are already barriers to their relevant control flow
02:29
<Bakkot>
devsnek: is the PL discord public?
02:30
<devsnek>
Bakkot: #lang-dev on the rust community discord
02:30
<devsnek>
(a channel about developing weird programing languages using rust, not about the development of the rust language)
02:31
<Bakkot>
thank
02:32
<Bakkot>
anyway I am going to be proposing do expressions with control flow disallowed
02:32
<Bakkot>
since I think everyone agrees on that subset
02:32
<Bakkot>
someone with more willpower than me can fight the control flow fight later
02:32
<rkirsling>
all of it? or just abrupt completions?
02:33
<Bakkot>
rkirsling break/return/continue crossing the do{}, specifically
02:33
<rkirsling>
cool
02:33
<Bakkot>
those are the only things people fight about
02:33
<rkirsling>
yes
02:34
<rkirsling>
if and try seem enough for a presentation
02:39
<ljharb>
i missed a log, but do expressions do not obviate the need for pipelines for me.
02:39
<ljharb>
they would be a solution, but not an ergonomic one for the use cases i have.
02:40
<Bakkot>
ljharb do you have examples of those use cases?
02:41
<ljharb>
i have the HOC one above
02:41
<ljharb>
those are in modules where the result is just export defaulted; local vars would work fine, but that looks way worse than the )))) versión already, let alone the pipeline one
02:41
<devsnek>
oh wow someone's proposing spaceship operator
02:41
<ljharb>
the desire is to have a chain of functions, just like you’d have a chain of OO methods
02:42
<ljharb>
do expressions only satisfy the “statements in expression position” part, which imo is not something i care about for pipeline
02:42
<ljharb>
devsnek: Hemanth and i yes
02:42
<Bakkot>
ljharb hmmm
02:42
<ljharb>
devsnek: well, we’re proposing that we solve a problem. Spaceship is just what we think solves it best ;-)
02:43
<devsnek>
bradleymeck: for the arbitrary module names slides, you can have cjs facades, even autogenerated
02:44
<devsnek>
ljharb: you should lead with s/a - b/a <=> b/ for array sorting
02:53
<Bakkot>
I do not understand the relationship between <=> and Array.prototype.compare
03:01
<ljharb>
Bakkot: the latter is comparison for arrays. The former is a comparison protocol for everything.
03:02
<ljharb>
if the array method and the operator both exist, then I’d expect the method to delegate to the symbol on array.prototype
03:04
<devsnek>
there's a standard c extension which allows expression blocks
03:05
<devsnek>
and it allows control flow
03:05
<Bakkot>
it also allows crashing compilers pretty regularly
03:05
<Bakkot>
c has a lot of extensinos
03:05
<Bakkot>
*extensinos
03:05
<Bakkot>
ugh
03:05
<Bakkot>
woords
03:05
<Bakkot>
wooooooords
03:05
<Bakkot>
*extensions
03:05
<Bakkot>
if you're looking for an example which allows control flow, ruby's blocks are probably more relevant
03:06
<devsnek>
so far every example i find allows it
03:06
<ljharb>
every language allows reflection on private things too :-) we can be better
03:07
<Bakkot>
most languages just don't allow statements in expression position at all
03:07
<devsnek>
yeah but people don't say its a mistake
03:07
<Bakkot>
the languages which do tend to have that as their philosophy, so it makes sense to allow control flow there also
03:07
<Bakkot>
we are grafting this feature onto a language which already has an expression/statement dichotomy
03:07
<Bakkot>
so our situation is somewhat unique
03:07
<devsnek>
c has the same issue
03:08
<devsnek>
point taken about crashes but still
03:08
<Bakkot>
I would seriously not use GCC-specific extensions as precedent for anything ever
03:08
<Bakkot>
they are 100% added because they solve a specific use case someone had, not coherently designed to be a reasonable feature
03:08
<rkirsling>
^
03:08
<devsnek>
clang supports it too
03:09
<rkirsling>
I mean that's not unusual though
03:09
<rkirsling>
clang strives to be GCC compatible
03:09
<devsnek>
msvc doesn't support it
03:09
<devsnek>
but msvc is also kind of broken in general
03:12
<rkirsling>
I mean...maybe so but I don't think this exemplifies that in any way
14:59
<ystartsev>
devsnek: will you be doing an update on iterator helpers?
15:03
<devsnek>
ystartsev: no :(
15:04
<devsnek>
ystartsev: did you see the conversation in #tc39-implementers
15:04
<ystartsev>
devsnek: since we are starting to implement, it would be great to have a discussion about the generator stuff you and jorendorff were trying to figure out
15:04
<ystartsev>
yes
15:04
<devsnek>
ok cool
15:04
<ystartsev>
would you be ok if i started a conversation about that?
15:05
<devsnek>
wdym by conversation
15:13
<ystartsev>
devsnek: primarily, a clarification of the positions of the editors and the champion (so, you) regarding how generators should be used in the spec
15:13
<ystartsev>
this is so that we can move forward with the implementation. it wouldn't be stage advancement, just discussion
15:13
<devsnek>
oh i meant like what medium
15:13
<devsnek>
plenary discussion?
15:13
<ystartsev>
oh, as an agenda topic
15:13
<ystartsev>
yep
15:14
<devsnek>
sure, sound fun
15:14
<devsnek>
sounds*
15:14
<ystartsev>
cool. i will add it
15:14
<ystartsev>
and maybe make some slides based on your discussion with jorendorff
15:14
<devsnek>
👍🏻
15:14
<devsnek>
thanks for working on this
15:15
<ystartsev>
sure, happy to help!
18:47
<bradleymeck>
can anyone give my eyes some help, i wrote up https://gist.github.com/bmeck/5f195c4ae08009db4f3eefdc8bb360c9 to see if anything is using Symbol.species on their pages for Arrays and TypedArrays, but *nothing* is hitting that code except a coreJS eager feature detection. I feel like I definitely did something wrong
18:53
<ystartsev>
bradleymeck: it should work for this example right?
18:53
<ystartsev>
https://www.irccloud.com/pastebin/KlTA1VIh/
18:54
<bradleymeck>
yea, i see the bug I hit
18:55
<bradleymeck>
coreJS makes species a regular function not a constructor so when I was patching that to figure out the noise ratio i broke everything else
18:55
<bradleymeck>
`species().foo` should be in a try catch
18:55
<bradleymeck>
well technically we could always use new?
18:56
<bradleymeck>
ystartsev: the goal is that we detect that code, yea
18:57
<bradleymeck>
well that we detect when the species in the subclass is not the builtin*
18:58
<bradleymeck>
cause if the behavior changes to always use the builtin we aren't concerned with the subclass species being the builtin
18:58
<ystartsev>
yes
18:59
<ystartsev>
sorry the code snippit was wrong, shouldn't be set to array
18:59
<bradleymeck>
thanks for the sanity glance
19:03
<ystartsev>
its hitting for me, ill post the snippit in case i did something wrong
19:04
<ystartsev>
can you see this? https://gist.github.com/codehag/2aaa571b6286f7f2cc28d01736c7e708
19:04
<bradleymeck>
i'm just skeptical of these sites that are extending builtins via some regexps showing things like `extends Array` but never hitting any species usage
19:04
<bradleymeck>
i can see it, let me run it
19:04
<ystartsev>
one thing that is surprising to me is that we are not seeing angular show up
19:05
<ystartsev>
https://github.com/angular/angular/commit/58b29f1503a180fdfb8feb73a30d0c4448afad9a
19:05
<ystartsev>
i feel like we should see that?
19:06
<bradleymeck>
yea that gist hits the trap
19:06
<ystartsev>
oh! good
19:06
<ystartsev>
oh wait, my gist, yea that makes sense
19:06
<bradleymeck>
idk if angular hits it, but if you have a specific site i can visit to verify that would be good
19:07
<ystartsev>
lemme look
19:07
<bradleymeck>
angular vs angularjs still confuses me a bit
19:08
<bradleymeck>
ystartsev: i did disable Promise detection is likely why? I can re-enable it
19:09
<ystartsev>
this project hits it... don't know much about it
19:09
<ystartsev>
https://github.com/microsoft/ApplicationInsights-node.js
19:10
<ystartsev>
or this is better: https://zonejs-basic.stackblitz.io/
19:11
<shu>
i can't understand the angular code
19:12
<shu>
it seems to be trying to follow the @@species protocol but doesn't depend on the native Promise.then, since it also patches then
19:13
<bradleymeck>
ystartsev: that page does not fire it, i've been trying to poke it to see if the detection is slightly off
19:14
<bradleymeck>
it doesn't use the builtin at least
19:15
<ystartsev>
interesting
19:15
<ystartsev>
might be a good example though, shows how species is not being used as expected anyway
19:16
<shu>
i have no problems with user libraries themselves using @@species as their own subclassing machinery
19:16
<ystartsev>
this is another example, they have a few https://stackblitz.com/edit/zonejs-throttle?file=index.js
19:16
<shu>
they don't have the implementation tradeoffs of native engines
19:16
<ystartsev>
yeah it looks like that is pretty much what angular did
19:16
<bradleymeck>
out of 1k sampled sites out of 400k, all 26 traps were from coreJS so i was losing my mind
19:17
<ystartsev>
shu: you mentioned that we should formulate a bigquery for this
19:17
<shu>
ystartsev: bradleymeck has already done great work there
19:17
<ystartsev>
oh great
19:17
<ystartsev>
ok, because i wasn't sure where to start
19:17
<shu>
ystartsev: though if you want to start playing with it, either send *me* queries to run, or wait until i can figure out how to get you GCP credits
19:17
<shu>
because it turns out it is expensive af
19:17
<ystartsev>
i have no idea how to forumate them, i would need to do some reading
19:17
<bradleymeck>
i have the output if you want, but its mostly just 20mb of pages in a CSV we need to actually validate against
19:17
<shu>
ystartsev: it's SQL
19:18
<shu>
that may not solve your problem :)
19:18
<ystartsev>
oh, thats straight forward
19:18
<shu>
i don't really know SQL, so that was my problem
19:18
<ystartsev>
its basically prolog but all caps right?
19:18
<devsnek>
select * from websites where breakage=true
19:18
<devsnek>
it doesn't have to use caps i don't think
19:19
<ystartsev>
bradleymeck if you have the data and the queries i would love to take a look
19:19
<ystartsev>
maybe we can make a doc about it for how-we-work
19:20
<bradleymeck>
ystartsev: DO NOT RUN the query I'm about to post, it is a bit pricey we found out
19:20
<ystartsev>
the angular story is really interesting because it tells us that people don't subclass the way we thought they would, and it gives more of a reason to remove this
19:20
<ystartsev>
:| gotcha
19:20
<bradleymeck>
https://www.irccloud.com/pastebin/Oyd05gui/dont_run_this
19:20
<bradleymeck>
we have saved output of it
19:20
<ystartsev>
cool
19:21
<ystartsev>
ah gosh i need to stop working on this, its super late
19:21
<ystartsev>
i am going to _call it a day_
19:21
<ystartsev>
but i am very excited about this
19:21
<bradleymeck>
cya! enjoy the break
19:21
<devsnek>
how big is the dataset
19:22
<bradleymeck>
not as huge as I thought, our first naive query was like 6k and this one is up at around 400k
19:22
<bradleymeck>
after you dedup the page hrefs
19:42
<shu>
bigquery should rename FULL JOIN to EXPENSIVE JOIN
19:59
<bradleymeck>
shu we got another coreJS noise flag apparently with https://github.com/aldehydkrotonowy/source-code/blob/6bf6ff94a485bedb02218978a62dd2881c0c54d6/core-js/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js#L22
20:00
<bradleymeck>
gah, linked to wrong line, but yea that file also does eager detection
20:03
<bradleymeck>
https://github.com/zloirock/core-js/blob/master/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js#L80 is the actual line, reading
20:05
<devsnek>
this code shouts too much
20:14
<bradleymeck>
shu: it looks like if the detection fails it replaces the builtins with its own there
20:19
<bradleymeck>
it is odd though, i only saw it because they use {} and call ({})[RegExp.prototype[Symbol.split]]('')
20:20
<bradleymeck>
https://github.com/zloirock/core-js/blob/master/packages/core-js/internals/fix-regexp-well-known-symbol-logic.js#L70-L73 sets the species for the ordinary object, but idk why, they don't seem to check the return value to be the same
21:03
<shu>
bradleymeck: i am on PTO today since Google gave everyone off, let's pick it up on tuesday. feel free to send me a gist or an email with the cases you find
21:03
<bradleymeck>
k
21:08
<bradleymeck>
another trap fires for Promise.then in https://github.com/zloirock/core-js/blob/717ff8bca8e68508ef6cef7eb673d0b39265739a/packages/core-js/modules/es.promise.js#L76 it seems
21:09
<shu>
a false positive or?
21:10
<bradleymeck>
unclear... the code is really abstract everytime i have to cross ref all these files for corejs
21:10
<bradleymeck>
it looks like it replaces Promise if it is wrong
21:11
<bradleymeck>
we likely should make a test/script to just punch away the globals ourselves and see what breaks
21:11
<Bakkot>
"see what breaks" is tricky, turns out
21:11
<Bakkot>
since almost all pages are throwing random errors all the time
21:12
<devsnek>
maybe a custom build of firefox or chrome that has prints in these @@species sections
21:12
<Bakkot>
and also have try-catch suppressing half of the errors
21:12
<devsnek>
anyone with sentry on their page
21:12
<devsnek>
will slurp up errors without you ever seeing them
21:14
<bradleymeck>
Bakkot: I'm more concerned with only the scope of these coreJS detection mechanisms
21:14
<bradleymeck>
the whole page is too big to reason about
21:15
<bradleymeck>
i'm already patching stuff in devtools, idk, you can't slurp up errors without me seeing them
21:16
<bradleymeck>
so far, all things i've read in the output are from coreJS
21:16
<bradleymeck>
which is kind of impressive?
21:16
<bradleymeck>
but it replaces builtins with its own stuff
21:17
<devsnek>
is it babel that inserts corejs
21:20
<ljharb>
often
21:20
<ljharb>
but not always
21:30
<bradleymeck>
a lot of these though are semi-easy to detect, like they construct a promise subclass that has fulfill and reject as the same function identity
21:31
<bradleymeck>
the real issue is wading through all the core-js history to see if the minified code matches up
21:31
<bradleymeck>
which at this point i'm just starting to assume it is all this feature detection
21:32
<bradleymeck>
i had to start labelling which kind of detection it is coming from, the only one i'm a bit scared of is the latest core-js i have to detect via the result of new species(...).constructor.name === 'FakePromise'
21:33
<bradleymeck>
but that gets minified out
21:33
<bradleymeck>
detecting species().constructor is typeof 'object' might be saner?