03:04
<devsnek>
engine262 rewrite now failing fewer than 10,000 tests 🎉
03:04
<leobalter>
Nice one!
03:04
<devsnek>
its mostly early errors at this point :(
03:04
<devsnek>
still don't have a great way to do early errors
03:05
<devsnek>
might rip out all the early error stuff i currently have and make it a second pass
03:07
<Bakkot>
traditionally early errors are part of the parser
03:08
<devsnek>
yeah still part of the parser api
03:08
<devsnek>
i mean like, `parseScriptBody` wouldn't be what checks for duplicate lexical bindings
03:08
<Bakkot>
I mean it could be
03:08
<devsnek>
everything is a mess
03:08
<devsnek>
`a.await` is a parse error rn
03:09
<devsnek>
i'm liking the idea of shift's reduce thing
03:46
<devsnek>
i wonder if it would be web compatible to make evaluators able to throw AggregateErrors instead of SyntaxError
04:17
howdoi
10,000 tests! wow!
13:26
<gibson042>
the link for Decorators slides at https://github.com/tc39/agendas/blob/master/2020/07.md and in the notes doc doesn't work, can someone involved with the proposal fix it?
15:11
<devsnek>
what if function parameters had elisions
15:12
<bradleymeck>
`Object.defineProperty(new Proxy({}, {getOwnProperty(o, k) {return {value:1}}}), 'why', {value:2})` is... strange
15:14
<bradleymeck>
`{ let o = new Proxy({}, {getOwnPropertyDescriptor(o, k) {return {value:1}}}); Object.defineProperty(o, 'why', {value:2}).why; }` => 2
15:14
<bradleymeck>
`{ let o = new Proxy({}, {getOwnPropertyDescriptor(o, k) {return {value:1}}}); o.why; Object.defineProperty(o, 'why', {value:2}).why; }` => 2
15:15
<bradleymeck>
{ let o = new Proxy({}, {getOwnPropertyDescriptor(o, k) {return {value:1}}}); Object.getOwnPropertyDescriptor(o, 'why'); Object.defineProperty(o, 'why', {value:2}); } => error
15:15
<bradleymeck>
you can read the non-configurable value
15:16
<bradleymeck>
and you can replace it, as long as you don't check if it is configurable
15:16
<Bakkot>
the `get` trap being distinct from the `getOwnPropertyDescriptor` trap is a bit weird, yeah
15:17
<Bakkot>
bradleymeck in your last example it's the `Object.getOwnPropertyDescriptor` which throws, not the `Object.defineProperty`
15:18
<bradleymeck>
also confusing
15:19
<bradleymeck>
you can read it, but not see its descriptor?
15:19
<bradleymeck>
what is this hell
15:22
<Bakkot>
> the `get` trap being distinct from the `getOwnPropertyDescriptor` trap is a bit weird, yeah
15:22
<bradleymeck>
i'm learning yea
15:27
<devsnek>
proxies are strange
15:29
<bradleymeck>
reflection always gets strange eventually
18:22
<bradleymeck>
what is a JS builtin that takes an options bag ?
18:22
<ljharb>
bradleymeck: 262 doesn't really have any, unless you count a Proxy handler, or Object.defineProperties/Object.create's second argument
18:23
<bradleymeck>
no, per the discussion we just had
18:23
<bradleymeck>
handler is thing which gets "this" value apparently
18:23
<bradleymeck>
options bag, doesn't
18:23
<bradleymeck>
defineProperties kind of?
18:23
<ljharb>
there's nothing in 262 that takes a function off an object and calls it directly
18:23
<ljharb>
in 402, there's tons of examples tho
18:24
<bradleymeck>
it doesn't really configure the algorithm
18:24
<bradleymeck>
should we cross ref 402 in the how-we-work term list?
18:35
<bradleymeck>
how about requisition() instead of upsert()/emplace()
18:36
<leobalter>
this proposal would be great if we had Decorators
18:36
<rkirsling>
ensure()?
18:36
<devsnek>
what if we made a new kind of function declaration
18:36
<devsnek>
that wasn't hoisted
18:37
<devsnek>
then we could just do normal style generators
18:37
<devsnek>
decorators*
18:41
<leobalter>
`await @all x`
18:42
<leobalter>
for me this looks better than `await.all x`, not going through stacking trace issues
18:43
<leobalter>
I'd be pretty satisfied with `await * x`, only giving sugar for Promise.all
18:43
<devsnek>
what about
18:43
<devsnek>
`for await concurrent (const x of y) {}`
18:43
<devsnek>
~= `await Promise.all(y.map((x) => {}))`
18:44
<leobalter>
devsnek: probably a separate discussion but I'd be up to discuss it as well
18:44
<Bakkot>
devsnek that interacts weirdly with abrupt completions
18:45
<Bakkot>
it seems like it would lead to a lot more concurrency bugs than the current patterns
18:46
<devsnek>
i guess the hard part would be deciding what `break` does
18:46
<devsnek>
everything else seems well defined
18:47
<Bakkot>
presumably `return` exits the function as soon as any iteration hits it, and it's just a race?
18:48
<Bakkot>
that is the "a lot more concurrency bugs" thing
18:48
<devsnek>
oh yeah return
18:48
<bradleymeck>
rkirsling: kind of, but idk how that implies potential update
18:49
<devsnek>
Bakkot: the map is more about mapping to async functions, not the result of those async functions
18:49
<Bakkot>
devsnek I am not sure what that means
18:49
<Bakkot>
or, like, why it matters
18:49
<Bakkot>
I know how Promise.all works I just don't know why you are mentioning this
18:50
<rkirsling>
bradleymeck: true. was all I could think of at that moment though
18:54
<devsnek>
this is interesting https://es.discourse.group/t/nan-trapping-operators/402
18:55
<bradleymeck>
rkirsling: .summon()?
18:55
<michaelficarra>
jackworks: the proposal I was referring to was https://es.discourse.group/t/array-prototype-uniqby/138
18:55
<rkirsling>
nice
18:55
<bradleymeck>
.claim is pretty good
19:01
<bradleymeck>
do we have any knowledge of static JS tools that assume after a map.has(k) === true that map.get(k) should get a value that does exist
19:01
<bradleymeck>
also how do people feel about .get(k) firing a user code trap?
19:15
<jridgewell>
devsnek: I think this is at the wrong poit
19:15
<jridgewell>
point**
19:15
<jridgewell>
You'd want to throw when you generate the NaN, not when you compare with it.
19:15
<jridgewell>
bradleymeck: Typescript doesn't, last I checked
19:15
<devsnek>
jridgewell: `nonanscope {}`
19:15
<jackworks>
devsnek: "`for await concurrent (const x of y) {}`" yeah, I always want to have some kind of concurrent control over `for await` loops. maybe even further, with args `for await concurrent 4` means max 4 running or `for await concurrent _identifier_` to refer a custom task dispatcher
19:17
<jackworks>
Bakkot: yeah, maybe we ban the "break" or "return" only leave "continue" in `for await concurrent` like the do expression did
19:21
<Bakkot>
jackworks yeah, though I would still worry about closed-over values
19:21
<jackworks>
I remember there was a "use strong" in v8 that will throw immediately when a math operation yielding NaN, I like that idea, not in the language, but as a debugger tool.
19:21
<Bakkot>
for loops it is very common to have, like, `let x; for (...) { if (test) x = whatever }`
19:21
<Bakkot>
which, if the loop is concurrent, is probably a bug
19:21
<Bakkot>
you can have the same thing with Promise.all, of course, but it is much harder to run into
19:21
<jackworks>
Oh maybe we can suggest v8 to add a "Pause on NaN calculation"
19:23
<jackworks>
"if the loop is concurrent, is probably a bug" yeah but since it is opt-in, developer should learn about what is race condition
19:24
<Bakkot>
ehhhhhhhhhhhhhhhh
19:24
<Bakkot>
concurrency bugs are notoriously one of the Hard Problems
19:24
<Bakkot>
I would be very, very reluctant to introduce an affordance which makes them easier to run into
19:25
<Bakkot>
I do not find "developers should be careful" a compelling argument in this case, especially given how hard concurrency bugs are to avoid in codebases that don't have Rust-style ownership or similar guarantees
19:25
<jackworks>
"Promise.all, of course, but it is much harder to run into" agree, but the problem is today, async concurrent calculation is pain to write `await Promise.all(arr.map(async x=> ...))` too tedious
19:29
<jackworks>
"very reluctant to introduce an affordance which makes them easier to run into" reasonable... so we just let async concurrent pain to write, to let devs write serial async code? at least for me, sometimes it's really safe to do the async concurrent calculation but I don't want to write `await Promise.all(arr.map(async x=> ...)) ` these bunch of code so I let it run in serial
19:31
<Bakkot>
I am happy to explore affordances which make it easier to write concurrent code; I don't think `await.all` would have the same problem as `for await concurrent`, for example
19:31
<jackworks>
I think WeakRef and FinalizationRegistry are applicable to the same argument. they're easy to misuse but they're still added to the 262 and mdn.io gives warnings on it "Avoid where possible"
19:32
<Bakkot>
We would never have added WeakRefs if they hadn't been necessitated by wasm
19:32
<jackworks>
lol
19:32
<Bakkot>
but they're a fundamental capability, whereas `for await concurrent` is not a fundamental capability
19:34
<jackworks>
my friend was working on the membrane, he also needs WeakRef; my RPC library provides iterating on remote async generators so I need WeakRef too
19:34
<Bakkot>
`for await concurrent` is about making certain kinds of code easier to write, which means we need to think hard about whether we in fact want those kinds of code to be easier to write, and my answer is no because that _particular_ syntax makes it much easier to have concurrency bugs, more than other possible affordances for writing concurrent code
19:34
<Bakkot>
yeah they're useful in other cases, it's just that they have way too many problems to justify for those cases alone
19:37
<jackworks>
hmm, so people will re-inventing it again and again and it's more easily to have bugs in their own impl
19:37
<jackworks>
is it possible to design a syntax to make it easy to write, meanwhile reduce the possible race condition bugs?
19:38
<TabAtkins>
Phew, I haven't had to write it yet myself, but `await Promise.all(arr.map(async x=>...))` is *awful* to write.
19:38
<TabAtkins>
`for await.all(const x of arr){...}` plz
19:38
<jackworks>
(WebCrypto API on mdn even gives a big strong red warning box writes "If you're not sure you know what you are doing, you probably shouldn't be using this API.")
19:40
<jackworks>
maybe the `for await.all` sugar is too sweet and people will start to abuse it everywhere leads tons of race conditions, then the eslint decides it's a super foot gun and ban it 🤣
19:43
<jackworks>
oh I recall a joke, when `async await` steps into our life, I saw an article says `await` is easy to get abused and new comer to JS will try to write `await` before any expression.
19:43
<Bakkot>
tbf people do that!
19:43
<Bakkot>
it just doesn't lead to bugs
19:43
<Bakkot>
so it's not a big problem
20:42
<bradleymeck>
name for a .get that defaults a value if no such key is present but does not insert it? (getDefault was seen as having either semantics)
20:42
<ljharb>
why not `.get(key[, default])`
20:43
<ljharb>
matches the current default of undefined
20:43
<Bakkot>
getOrDefault
20:43
<Bakkot>
or jordan's thing
20:44
<jridgewell>
`default` would need to be a function, there
20:44
<ljharb>
ah, true. can default to `() => {}`
20:45
<Bakkot>
getOrCompute
20:45
<devsnek>
getpute
20:45
<Bakkot>
jridgewell why "need"?
20:45
<ljharb>
winner
20:45
<Bakkot>
I see the use for it, just not the necessity
20:46
<jridgewell>
Because the default value can be very expensive to create
20:47
<Bakkot>
can be, but is that frequent enough that it is necessarily something which has to be met by this method?
20:47
<Bakkot>
for those cases, you can still do `if (!x.has()) x.put()` or whatever
20:47
<ljharb>
yes, in my experience
20:48
<ljharb>
it's often constructing an object or transforming data
20:48
<jridgewell>
To counter, you could just do `x.has(key) ? x.get(key) : default` for your case
20:48
<Bakkot>
right, of course
20:48
<Bakkot>
this is a question about frequency
20:48
<Bakkot>
in my experience, the cheap key is much more common
20:48
<Bakkot>
I am curious if your experience differs
20:49
<jridgewell>
cheap key?
20:49
<Bakkot>
*cheap default
20:49
<jridgewell>
Ah,
20:49
<jridgewell>
My use is templateing libraries
20:50
<jridgewell>
Particularly lit-html, which creates a whole `<template>` and children and walks the entire tree.
20:51
<Bakkot>
java has getOrDefault, which takes a value, and computeIfAbsent, which takes a lambda (and updates the map(
23:06
<TabAtkins>
I think a default-value factory is a requirement, yeah. Arrow functions make it cheap to define one for constant values, and they're necessary for expensive defaults.
23:07
<TabAtkins>
And I think the functionality should indeed just be added as a second parameter on .get().
23:08
<TabAtkins>
(Python separates default-value from default-value-factory, but Python also has annoying inline functions.)
23:33
<devsnek>
what if we allowed elisions in function parameters
23:45
<TabAtkins>
Elaborate?