03:09
<Bakkot>
there is not a formal process
03:09
<Bakkot>
that said, I'd suggest reaching out to the relevant people, including authors and champions, first
03:09
<Bakkot>
if nothing else to make sure you don't misrepresent their positions
05:23
<ljharb>
imo, definitely always ask first before you post about somebody. that said, if someone's championing a proposal they've kind of signed up for their name to be associated with it, so i'd be surprised if that was a problem
05:38
<ljharb>
did we want `eval?.(x)` to be considered a direct eval? https://github.com/tc39/test262/pull/2667
05:38
<ljharb>
it seems like we could choose to make it indirect
05:45
<rkirsling>
pretty sure that's a spec bug
05:48
<rkirsling>
JSC/SM/V8 all have a direct eval and I understood the intention to be "act as if the ?. weren't there"
05:48
<ljharb>
that's what the test is testing
05:48
<ljharb>
i'm asking, should `eval?.()` be an indirect eval instead
05:48
<ljharb>
because we want less direct evals, not more
05:49
<rkirsling>
I always have trouble remembering the implication there
05:49
<rkirsling>
but the point is we're not assigning anything
05:52
<ljharb>
sure, but given that `x?.(...a)` arguably desugars to `do { const tmp = x; tmp === null | tmp === undefined ? tmp : tmp(...a) }`, that'd be an indirect eval :-D
05:54
<rkirsling>
lol lol
05:54
<rkirsling>
oops
05:54
<rkirsling>
just meant one lol
05:56
<rkirsling>
I don't think that reflects anyone's actual viewpoint though
05:58
<rkirsling>
the user viewpoint can just think of ?: or && and the AST viewpoint can just wrap the eval call in an optional node
05:58
<ljharb>
sure, i get the easy arguments to direct
05:58
<ljharb>
i'm just wondering if it's a missed opportunity to kill more direct eval calls
06:10
<leobalter>
I wish we could have avoided the optional call form. This has sailed.
06:10
<ljharb>
is it really a web compat issue to change tho?
06:11
<leobalter>
It seems reasonable to have it as an indirect eval. I can’t read the specs right now (no computer at Sunday night policy at home)
06:11
<leobalter>
What does the spec says today?
06:12
leobalter
is lazy
06:15
<ljharb>
oh i assume it says it's direct, from that test262 PR, let me check
06:24
<ljharb>
"direct eval" links to https://tc39.es/ecma262/#sec-function-calls-runtime-semantics-evaluation , but it deals with cover grammars and MemberExpression and i can't tell if `?.` is part of that
06:31
<rkirsling>
the test262 PR is saying it's indirect
06:31
<rkirsling>
that's why I said there's a spec bug
06:31
<ljharb>
ohhhh ok
06:32
<ljharb>
i misread the OP then
06:32
<ljharb>
indirect seems better to me
06:32
<rkirsling>
yeah but everybody shipped with the intent of direct is the point
06:33
<leobalter>
PR is saying that, but apparently engines disagree. I’ll check the spec tomorrow.
06:33
<rkirsling>
it's possible Claude did that intentionally and none of us knew what to look for, but
06:33
<ljharb>
i hope it's an engine bug tbh
06:34
<rkirsling>
I think it's a spec bug either way if everyone read it wrong
06:34
<ljharb>
fair
06:39
<rkirsling>
hmmmmmmmmm
06:39
<rkirsling>
https://github.com/tc39/proposal-optional-chaining/issues/21
06:40
<ljharb>
looks like it's intentional
06:42
<rkirsling>
never heard of `(0,eval)(foo)` but if "going out of one's way for indirect eval" is a thing then I guess that'd give `eval?.()` a reason to exist beyond like, "it seemed weirder to ban it" (which was my understanding)
06:43
<ljharb>
new forms of direct eval are what should imo be avoided
06:44
<ljharb>
(`(0,x.y)()` is a common form in babel output for "don't bring the receiver along", fwiw)
06:46
<rkirsling>
ah cool
06:46
<rkirsling>
that's good to know
06:51
<ljharb>
i also often use it when i don't want nasty ES6 name inferencing breaking my anonymous function test cases
06:52
<rkirsling>
guess you'll have to apply that to logical assignment too then
06:52
<rkirsling>
that's too bad
06:52
<ljharb>
yup
17:25
<howdoi>
Bakkot: roger that!
17:27
<leobalter>
ljharb rkirsling: ok, reading specs ... I believe it's indirect. I can stress it out with step by step, not to long but can be boring
17:28
<ljharb>
thanks, i'd love to understand if you have the time :-)
17:47
<leobalter>
I'm writing it all down
17:54
<leobalter>
ljharb: rkirsling https://gist.github.com/leobalter/0b32f73470b134617bed170492cd2089
17:55
<leobalter>
please correct me if I'm wrong. It's Monday morning :)
17:59
<devsnek>
wouldn't be a monday morning without some discussion of indirect eval
18:01
<ljharb>
leobalter: i'm not clear on how you get from EvaluateCall to eval()
18:03
<devsnek>
ljharb: Call() calls eval
18:03
<devsnek>
the actual %eval%
18:05
<ljharb>
where does the fourth arg to `PerformEval` come from?
18:05
<devsnek>
https://tc39.es/ecma262/#sec-eval-x
18:07
<leobalter>
EvaluateCall, step 7, the Call will defer to eval, as devsnek mentioned. I just skipped that part but you can go to Call, then F.[[Call]] and https://tc39.es/ecma262/#sec-built-in-function-objects-call-thisargument-argumentslist
18:11
<ljharb>
ohh i see
18:11
<ljharb>
thanks
18:11
<ljharb>
makes sense to me
18:11
<devsnek>
https://gc.gy/60554244.png
18:11
<devsnek>
classic case of having too much abstraction
18:45
<devsnek>
doesn't this mean that babel/ts transforms for optional chaining are incorrect for eval?.()
18:59
<shu>
i feel like eval?.() should not be indirect eval
19:01
<ljharb>
why not
19:01
<ljharb>
?
19:06
<ljharb>
i can see the argument both ways, ofc, but it seems like when either answer makes sense we should pick the one that avoids the bad thing
19:07
<shu>
because the original motivation was analyzability, and a global `eval?.()` is perfectly analyzable. and a pretty weak simplicity argument: less stuff to remember if the property is "non-member calls to e-v-a-l" instead of "non-member non-optional calls to e-v-a-l-("
19:08
<shu>
the second argument being pretty weak since maybe for some folks just remembering "e-v-a-l-(" is the easier thing
19:08
<ljharb>
interesting, i didn't know the original motivation
19:08
<shu>
ljharb: it is THE backwards breaking change. without saying indirect eval didn't have access to the local bindings, i honestly think JS wouldn't have taken off the way it has
19:09
<ljharb>
i mean, i think i get why indirect eval matters
19:09
<ljharb>
i didn't think about it in terms of analyzability
19:11
<shu>
yeah we wouldn't have been able to put bindings on-stack otherwise
19:12
<devsnek>
direct eval is big deopt
19:12
<leobalter>
shu: in this case we need a normative change. I'm not opposed to any direction we pick. I'd prefer consistency with what web developers expect. And as a web dev, I see `eval?.(x)` as `eval ?? eval(x)`, in the direct form. That's totally debatable.
19:13
<shu>
leobalter: yeah, i agree we should err towards minimizing surprises for this one
19:13
<shu>
there're no good first-principles arguments
19:13
<devsnek>
i think the whole direct/indirect thing is weird enough that there is no useful rule to follow
19:13
<ljharb>
right, i think we can revisionist history to justify either decision equally
19:14
<devsnek>
https://gc.gy/60558260.png
19:15
<rkirsling>
PRNG has spoken
19:21
<rkirsling>
but yeah I don't want to implement this unless we're sure
19:21
<rkirsling>
seeing as we have consistency in what's shipping right now
19:21
<rkirsling>
it's a little weird to me that SM moved so quickly
19:21
<leobalter>
I wonder who is relying on eval today (they do exist, right?) and what they really expect. I'd find odd of anyone relying on the very specific `eval?.(x)` case. The test came in after an implementation for ESLint, so I don't think they care if it's direct eval or not other than for spec consistency.
19:24
<jridgewell>
I'm fine with whichever we choose
19:24
<jridgewell>
Side note: `eval ?? eval(x)` is incorrect, because it won't eval the RHS
19:25
<jridgewell>
I think we should add interrobang operator `!?` to do "RHS if LHS is non-nullish"
19:29
<rkirsling>
I can understand an argument for utility if `eval?.()` is easier than `(0,eval)()` but I don't think that implies that it's intuitive
19:29
<rkirsling>
it's kind of a fancy hack
19:30
<shu>
yeah i guess i don't really care
19:30
<jridgewell>
I think the easier option is to make it a direct eval
19:31
<jridgewell>
Because every implementation (except engine262) and transpiler uses direct eval
19:32
<jridgewell>
Ooo, XS does indirect, too.
19:32
<rkirsling>
yeah I think the reason we all agreed on it was because we were all understanding that the behavior of ?. is meant to be just the behavior without it, when the LHS is non-nullish
19:32
<jridgewell>
That makes sense to me.
19:33
<leobalter>
that was me trying to be smart instead of using &&
19:34
<ljharb>
jridgewell: wait, how is that incorrect
19:34
<ljharb>
jridgewell: `x?.(y)` is like `x ?? x(y)`, no? including the short-circuiting?
19:34
<ljharb>
(just not including the double evaluation of x)
19:35
<rkirsling>
no there's no call if you're satisfied with `x`
19:35
<jridgewell>
`x ?? y` is `x == null ? y : x`
19:35
<jridgewell>
`x?.()` is `x == null ? undefined : x()`
19:36
<jridgewell>
So `x ?? x()` is `x == null ? x() : x`
19:36
<jridgewell>
We invoke a `null`/`undefined`
19:36
<ljharb>
oh right, the opposite
19:36
<jridgewell>
Yah
19:37
<ljharb>
so it'd be like `x ‽ x(y)` i guess
19:37
<jridgewell>
So, interrobang does a not-nullish check, instead of a nullish check.
19:37
<ljharb>
right
19:37
<rkirsling>
or &&
19:37
<ljharb>
would it be !? or ?! tho
19:37
<jridgewell>
I like it because interrobangs should be a thing
19:37
<rkirsling>
?. is a more precise &&, ?? is a more precise ||
19:37
<jridgewell>
And `!?` reads "not nullish"
19:38
<ljharb>
would you then expect `a!?.b` even tho that be silly since it'd always throw?
19:38
<ljharb>
or only as a binary operator
19:39
<jridgewell>
> ?. is a more precise &&
19:39
<jridgewell>
Only if you mean property access. Doesn't work well for root value
19:39
<jridgewell>
Only the binary operator, `!?.` makes no sense (and is already valid-but-bad typescript code)
19:39
<ljharb>
right
19:39
<rkirsling>
but `??` can be read as "falls back to" and to `?.` covers the `&&` guarding usage so
19:40
<jridgewell>
Only if you're doing property access
19:40
<rkirsling>
I don't think this `!?` would actually be very useful...I think it could really confuse wrt ?.
19:40
<jridgewell>
Babel had a case with private optional
19:41
<jridgewell>
Where we do `obj == null : undefined : getPrivate(obj)`
19:41
<jridgewell>
And that can't be represented with either `?.` nor `??`.
19:41
<jridgewell>
We need interrobang to do it.
19:42
<jridgewell>
So, `??` is stricter `||` and `!?` is stricter `&&`.
19:42
<ljharb>
i don't think ?? is a stricter ||
19:42
<ljharb>
stricter || would be "true or false" instead of "truthy or falsy"
19:42
<jridgewell>
And `?.` is a special case of `&&` for property access/call
19:43
<rkirsling>
I'm just saying, this whole tangent started because of a genuine mistake where !? wouldn't have actually been appropriate
19:44
<rkirsling>
and viewing !? as a solution is dangerous if it's going to confuse people that should be using ?.
19:44
<jridgewell>
`!?` is the appropriate solution, though.
19:45
<jridgewell>
`eval !? eval('test')`
19:45
<rkirsling>
but that code should never be written
19:46
<jridgewell>
The Babel case needed it, too.
19:47
<rkirsling>
sure I get that you already came up with it previously for that reason, yeah
20:19
<rkirsling>
seems like the case you gave could be handled _inside_ the function instead though, and while `!?.` would be nonsensical, `!?=` would be expected, yet of questionable utility
20:19
<rkirsling>
the issue is that with || and &&, truthy and falsy are on equal footing
20:20
<rkirsling>
nullish can never be on equal footing with non-nullish because if we could go back and do things over again, we would just have null and not nullish
20:23
<rkirsling>
so even though ?? and ?. bear similarity with these, there's a baked-in notion of "falling back" since it's all about convenient null-guarding and not about two similar buckets
21:06
<littledan>
Hey everyone, let's try to keep technical discussion in #tc39 when possible, so it's publicly accessible
21:07
<jridgewell>
But this is publicly accessible?
21:07
<ljharb>
littledan: this channel is publicly accessible already
21:07
<ljharb>
the only place we can't have technical discussions is the reflector.
21:08
<littledan>
I'm not talking about in terms of policy requirements, but we have more non-delegates hanging out in #tc39, since we advertise the existence of #tc39 publicly
21:08
<littledan>
(sorry, my comment was imprecise)
21:08
<ljharb>
sure. but sometimes we don't want to have the discussion with non-delegates, and that's what this channel is for
21:08
<littledan>
ok
21:09
<rkirsling>
sometimes it's just inertia over where a topic started
21:09
<rkirsling>
or like
21:10
<rkirsling>
if there's multiple topics then our channel count is effectively our thread count
21:10
<rkirsling>
hehe
22:20
<rickbutton>
spec question: is it valid to use a spec-List as a `this` argument to a function `Call`? (specifically, the `this` argument of the `adder` in a usage of `AddEntriesFromIterable`. it is mentioned that spec-types should not be used as object properties or variable values, but does that also apply to `this`?
23:21
<ljharb>
rickbutton: it's not valid
23:21
<ljharb>
rickbutton: spec values can't be exposed to user code
23:22
<ljharb>
rickbutton: in the AddEntriesToIterable case, you could argue that it's not exposed, but that'd be an editorial question the editors haven't previously had to consider
23:35
<rickbutton>
makes sense.
23:37
<rickbutton>
I don't think I will be able to re-use AddEntriesFromIterable in that case, will have to create a new op. either way its a small amount of spec