02:18
<devsnek>
bakkot i think u got a good solution to my question
02:18
<devsnek>
zip shortest + make everything except the first one infinite
02:44
<bakkot>
zip-longest is actually the interesting one; my thing does not give you that unless you know up front which the longest one is
02:57
<bakkot>

shortest I can come up with in ten minutes is

def zip_longest(*parts, fillvalue=None):
  sigil = {}
  return map(
    lambda p: tuple(map(lambda x: x if x is not sigil else fillvalue, p)),
    takewhile(
      lambda p: not (all(map(lambda x: x is sigil, p))),
      zip(*(chain(x, repeat(sigil)) for x in parts))
    )
  )

which... I guess it's straightforward enough, but I get why python decided that was worth putting in the standard library

15:00
<devsnek>
itertools docs has examples for how to implement the functions https://docs.python.org/3/library/itertools.html#itertools.zip_longest
15:45
<bakkot>
yeah but their implementation is an explicit loop, which is gross
17:23
<jschoi>
Has anyone thought about proposing a logical-xor operator ^^ to parallel bitwise xor ^?
17:25
<jschoi>
It was asked for and talked about on the TypeScript side, where it was closed with “making new binary operators is TC39's job, not ours”. https://github.com/microsoft/TypeScript/issues/587
17:26
<bakkot>
jschoi: what's wrong with !==?
17:27
<bakkot>
obviously it doesn't do the type coercion for you but I would be very reluctant to introduce a new operator which is only necessary when you don't know the types of your variables
17:27
<jschoi>
Yep, that was brought up in the TypeScript issue too. My answer is: nothing! I’m not seriously considering it, but I am wondering if it was considered, especially given that the ^ punctuator might be used for other purposes in the future.
17:28
<bakkot>
I don't recall seeing a discussion; you could check the mailing list archives at esdiscuss.org/, but I'd be surprised if there was any serious proposal put forward
17:29
<jschoi>
Yeah, I couldn’t find anything on ESDiscuss. But it’s good to know that the temperature for a binary ^^ in TC39 is cold. The pipe operator might use ^, after all, which would forever preclude a binary ^^. Thank you!
17:57
<devsnek>
bakkot: it doesn't seem to me like the new tail call wording behaves well with the "caller realm" for eval
17:57
<devsnek>
with the old wording the stack was popped, now it is not. which realm should it point to?
18:01
<bakkot>
devsnek: eval isn't a tail call anyway; I don't understand the question
18:01
<devsnek>
wdym it isn't a tail call
18:01
<bakkot>
https://tc39.es/ecma262/#sec-function-calls-runtime-semantics-evaluation
18:02
<bakkot>
a direct eval doesn't go through the normal call semantics
18:02
<bakkot>
it has its own branch, which doesn't include the tail call stuff
18:02
<devsnek>
you can do return (0, eval)() though
18:03
<bakkot>
oh, for indirect eval, sure
18:04
<devsnek>
so its like 2nd to top or 3rd to top depending on if there's a tail call now
18:04
<bakkot>
no, it's still the second to top
18:04
<bakkot>
the realm is no longer the realm of the caller of the function containing the tail call
18:04
<bakkot>
that was the point of the PR
18:04
<devsnek>
?
18:04
<bakkot>
the realm used for g in function f(){ g() } is the same as the realm for g in function f(){ return g() }
18:05
<bakkot>
that was the point of the PR
18:05
<devsnek>
i'm not following
18:07
<bakkot>
prior to #2495, when you had a g which could observe its callers realm, e.g. if g is a revoked proxy for a callable,
it would observe the realm of the caller of f in function f(){ return g() }, and now it observes the realm of f itself, just as for function f(){ g() }
18:07
<devsnek>
no i mean, if that's the case, isn't the assertion incorrect
18:07
<devsnek>
since you are continuing to use information from it
18:08
<bakkot>
eh, depends on what you consider "resources"
18:08
<bakkot>
we have consensus for allowing cross-realm tail calls to consume resources anyway, we just never merged that change in to the spec (and I don't plan to)
18:10
<devsnek>
it just weirds me out
18:11
<devsnek>
and if we explicitly differentiate between implementation activations of functions and the execution context stack, why do we also have to duplicate the context in asyncfunctionstart
18:12
<devsnek>
i feel like i'm missing a connection here or there is a mistake
18:13
<bakkot>

if we explicitly differentiate between implementation activations of functions

I don't know what this means. the spec does not use the phrase "implementation activations of functions"

18:13
<devsnek>
For example, a tail position call should only grow an implementation's activation record stack by the amount that the size of the target function's activation record exceeds the size of the calling function's activation record. If the target function's activation record is smaller, then the total size of the stack should decrease.
18:14
<bakkot>
that's in a non-normative note, which is talking about implementation strategies
18:14
<bakkot>
there's no corresponding notion in the normative prose
18:15
<devsnek>
i think the normative text was written with that model in mind
18:16
<devsnek>
and it makes it weird
18:16
<bakkot>
it was written with that model in mind, but it was extremely confused, because it was conflating that with transfers of control
18:16
<bakkot>
now there is no such conflation; it is much better
18:19
<bakkot>

re:

why do we also have to duplicate the context in asyncfunctionstart

it's so that when the topmost context suspends (that is, the body of the function does await), control will return (after a couple of intervening steps) to EvaluateAsyncFunctionBody step 5, which is the correct next step to evaluate

18:20
<bakkot>
if we didn't push a new context the await would suspend the execution context which has EvaluateAsyncFunctionBody itself, which is no good
18:22
<devsnek>
yeah i know the reasoning there (we had to revert my pr remember?), my point was there seems to be disagreement about what thing is doing the evaluation of code. is the execution context metadata for the evaluation or does it represent the evaluation itself
18:28
<bakkot>
from the spec's point of view, code is just another kind of data which gets passed around. the execution context stack represents some metadata which is tracked during evaluation - e.g. [[Realm]] - as well as representing nonlocal transfers of control within the spec [but n.b. this is within the spec's abstract machine, not within ecmascript code]: an execution context can be suspended-and-popped, which transfers control back to the step subsequent to the one which pushed it, and for execution contexts which have steps after the suspend-and-pop, at some future point it can be pushed-and-resumed and control will resume at the step subsequent to the suspend-and-pop.
18:29
<bakkot>
I'm not sure if this answers "what thing is doing the evaluation of code", though. not sure if by "code" you mean ES code or the spec steps.
18:35
<bakkot>
("execution contexts which have steps after the suspend-and-pop" is synonymous with "execution contexts which are created for the evaluation of generators/async functions/async generators/TLA modules", i.e., contexts which can use Yield or Await)
18:35
<bakkot>
sometimes algorithms which do suspend-and-pop use Return to transfer control back to the previous execution context, which is very strange; see https://github.com/tc39/ecma262/issues/2400 for discussion/a possible fix