00:26
<devsnek>
:w
00:26
<devsnek>
oops
18:40
<bradleymeck>
devsnek: new variable declarator kind?
18:40
<devsnek>
bradleymeck: hmm?
18:41
<bradleymeck>
def {x,y} = pt; pt.translate(1,1); def {x,y} = pt;
18:41
<bradleymeck>
though questions of shadowing get confusing due to JS having hoisting
18:42
<ljharb>
is that just a re-declareable var?
18:42
<ljharb>
*let, sorry
18:42
<devsnek>
yes
18:42
<devsnek>
that's what i originally suggested
18:42
<devsnek>
i feel like there's a stage 1 proposal here
18:45
<shu>
agree with bradleymeck on hoisting
18:45
<shu>
seems very confusing given hoisting. which one gets closed over?
18:45
<bradleymeck>
shu: i mean, thats the only real complaint left with the repl goal
18:46
<bradleymeck>
in other languages it is via source location, which honestly would be fine, but diff problem than repl has
18:48
<devsnek>
the rule i'm imagining is
18:48
<devsnek>
if the code would cause a redeclaration error
18:49
<devsnek>
make it valid
18:49
<devsnek>
leave everything else untouched
18:49
<bradleymeck>
so they point to the same storage?
18:49
<bradleymeck>
thats what v8 did for making their repl design doc
18:50
<devsnek>
i think either they're the same variable or you invalidate the old ones
18:50
<devsnek>
invalidating seems needlessly annoying
18:50
<ljharb>
`sudo let x`
18:51
<rkirsling>
ljharb: 👏
18:52
<ljharb>
could also reassign consts that way
18:53
<devsnek>
`sudo eval = undefined`
18:53
<bradleymeck>
proposal: make const less constant
18:53
<bradleymeck>
free me of linter errors!
18:53
<devsnek>
proposal: `let const`
18:53
<devsnek>
also `const mut`
18:54
<bradleymeck>
`let let let = 1` gasp a new tier
18:54
<shu>
why is redeclaring important in js exactly?
18:54
<bradleymeck>
i think it is just convenient in other langs
18:54
<bradleymeck>
that was the point
18:54
<shu>
do these other langs have types and benefit from being able to shadow a same-named declaration with a differently typed one?
18:54
<rkirsling>
I think this is just a repl impl issue
18:55
<shu>
ah, for repls that makes sense
18:55
<rkirsling>
redecl in a static file is bad news
18:55
<rkirsling>
(I'm not representing the discussion here though, that's just my view)
18:56
<devsnek>
shu: i just hate putting destructuring reassignments in parens
18:56
<devsnek>
ts users could benefit from the type thing you mentioned though
18:56
<devsnek>
rust allows that too and its very nice
18:56
<rkirsling>
ohhh that was your motivation
18:56
<shu>
the destructuring thing doesn't seem that compelling to me
18:56
<shu>
the TS one i have to think about
18:57
<devsnek>
yeah this is like
18:57
<devsnek>
a nit of a feature
18:57
<rkirsling>
I'm kind of unclear on why type-shadowing wouldn't be dangerous though
18:57
<devsnek>
which is why i didn't think it warranted new syntax
18:57
<devsnek>
it might be dangerous in ts due to the laxness of its type system
18:58
<devsnek>
or maybe taken in stride
18:58
<shu>
rkirsling: the *only* case where it's kind of legit, and probably the one devsnek ran into in Torque, V8's DSL, is where you cast an argument
18:58
<devsnek>
ah yeah that's the same as rust
18:58
<rkirsling>
oh from something void*-esque to what it really is?
18:58
<shu>
e.g., in pseudo-ish code `function f(xArg: Any) { let x = Cast<T>(xArg); }`
18:58
<shu>
yes exactly
18:58
<rkirsling>
yeah
18:58
<shu>
i don't know of other places where shadowing with different type is a good idea
18:58
<devsnek>
except you can do `x: Any` and `let x = Cast<T>(x)`
18:59
<shu>
that is far from sufficient motivation for allowing redecls in general imo
18:59
<devsnek>
yeah its not like the most revolutionary deature
18:59
<rkirsling>
that's kind of surprising even without the redecl though
18:59
<devsnek>
feature*
18:59
<rkirsling>
that `{ let x = ... x ...;} ` is allowed
18:59
<shu>
yeah actually with JS's parameter scope rules that isn't a redeclaration
19:00
<devsnek>
its not valid due to tdz though
19:00
<devsnek>
actually in strict mode its also invalid to declare the name
19:01
<devsnek>
or maybe all modes
19:01
<devsnek>
yeah all modes
19:01
<rkirsling>
at top-level function scope sure, but you could block it
19:01
<rkirsling>
can't get around the TDZ though
19:01
<devsnek>
anyway yeah this is one of those features that's too small to feel justified
19:02
<rkirsling>
yup
19:02
<devsnek>
we could add it in variables v3
19:02
<rkirsling>
lol
19:02
<devsnek>
(`val` and `val mut`, eta 2030)
19:02
<rkirsling>
if this wasn't about redecl and was simply about destructuring assignment to existing bindings then maybe there's something there
19:03
<rkirsling>
but only if it didn't add to the syntax budget
19:03
<rkirsling>
which seems unlikely to achieve
19:03
<devsnek>
right if you want to separate those two item
19:03
<devsnek>
items
19:11
<Bakkot>
devsnek if you don't like parens for destructuring you can use `0,` instead
19:11
<Bakkot>
`let x; 0,{ x } = { x: 1 };
19:11
<devsnek>
that's almost worse
19:11
<Bakkot>
it's better 'cause it's local!
19:12
<devsnek>
though it makes me wonder
19:12
<devsnek>
`void`?
19:12
<Bakkot>
i.e. you don't have to put parens at the end
19:12
<devsnek>
omg are you kidding me
19:12
<Bakkot>
I am not entirely serious, no
19:12
<devsnek>
that really binds as `(void { a }) = 1`?
19:12
<Bakkot>
yeah
19:12
<devsnek>
sad times
19:12
<Bakkot>
assignment expressions are very low precedence
19:12
<rkirsling>
oh god the comma
19:13
<rkirsling>
what a truly horrific invention
19:14
<Bakkot>
you know I was pretty much joking but looking at it it's kind of growing on me
19:14
<devsnek>
that "horrific invention" is the basis of minifiers, have some RESPECT
19:14
<rkirsling>
lolol
19:15
<devsnek>
ok new proposal idea
19:16
<devsnek>
somehow allow `void AssignmentExpression`
19:18
<Bakkot>
you could allow it in statement position easily enough, I think
19:19
<Bakkot>
tricker in expression position
19:19
<Bakkot>
or, well, it might be easy I'm just less sure if the obvious thing would work
19:19
<Bakkot>
and can more readily convince myself it works in statement position
19:19
<rkirsling>
Bakkot: lol I shared that with a colleague and he was like "if only it worked for `() => 0,{ bar: 42 }`"
19:19
<Bakkot>
rkirsling ha
19:20
<Bakkot>
that one I am happy to write the parens
19:20
<Bakkot>
and also happy that comma doesn't work
19:20
<rkirsling>
agreed, just made me laugh
19:21
<devsnek>
that comma works perfectly don't @ me
20:47
<devsnek>
shu: are you worried about people setting really high maximum values on resizable buffers in order to get around the resize limit
20:48
<devsnek>
s/resize limit/maximum size limit/
20:49
<leobalter>
This is not slack but I basically need some @channel for the broad message:
20:49
<devsnek>
i feel like the primary use case for resizing is that you don't know what the maximum will be
20:49
<leobalter>
if you consume Test262, please read this: https://github.com/tc39/test262/issues/2699
20:49
<shu>
devsnek: not really, why?
20:50
<devsnek>
like i said above
20:50
<devsnek>
i don't think wasm requires a maximum limit either
20:50
<shu>
it does for shared
20:51
<shu>
but that doesn't answer why i might be worried about people setting really high maximum values?
20:51
<devsnek>
cuz that's how you would get around the problem
20:52
<devsnek>
and browsers might not want people falling into that pattern
20:52
<devsnek>
idk
20:52
<shu>
i don't understand the full concern, that because applications do not know ahead of time what their max buffer size is, they will reserve something huge?
20:53
<shu>
and that reserving something huge is bad because... they cause their own application to run out of address space?
20:53
<devsnek>
right, that seems like a bad pattern
20:53
<shu>
that seems no worse than if someone wants to do that today, they would either commit to a huge buffer today
20:53
<shu>
or they keep making new buffers and copying
20:53
<devsnek>
well the point of resizing is that you don't commit to huge
20:53
<devsnek>
i don't get this
20:54
<shu>
you commit to the address range, but you do not commit to the actual memory
20:54
<shu>
what do you not get? did you read the motivation?
20:54
<devsnek>
yeah
20:54
<shu>
is there a part of the motivation that you don't understand, or you disagree with the motivation?
20:54
<devsnek>
ok so for example
20:55
<devsnek>
i have this package called earl
20:55
<devsnek>
that converts js values into erlang term format buffers
20:55
<devsnek>
ideally you start smallish and only grow if needed
20:55
<devsnek>
the main performance hit rn is growing, i have to allocate a new buffer and copy everything over
20:56
<devsnek>
resizing sounds great
20:56
<shu>
for that use case, is it important that you keep the identify of the ArrayBuffer the same?
20:56
<devsnek>
no
20:56
<shu>
then you should be using transfer() which i am reviving as part of this proposal
20:56
<shu>
Resizable buffers are for in-place grwoth
20:56
<shu>
if your issue is you need zero-copy growth, realloc semantics are sufficient, and that should be used instead
20:57
<devsnek>
so realloc is possible?
20:57
<shu>
what do you mean by "possible"?
20:58
<devsnek>
your explainer says that realloc is bad because xyz and so you want to avoid it
20:58
<devsnek>
which is fine
20:59
<devsnek>
but if transfer doesn't avoid it
20:59
<devsnek>
then why are you avoiding it with resize
21:00
<shu>
because there are two use cases
21:01
<shu>
1) an in-place growable buffer like wasm has, so that an underlying buffer can grow without requiring buffers and TA views be remade. that use case requires the identities of the buffers and TAs to stay the same. related is the webgpu re-pointing use case
21:01
<shu>
2) realloc for arbitrary growing and shrinking, avoiding copying where possible. this use case doesn't care about the identity of the buffers and TAs and can make new JS objects if needed
21:02
<devsnek>
i don't get why these are exclusive
21:02
<shu>
semantically, they are not. implementation and security experience says otherwise
21:02
<devsnek>
is there some inherent thing about security and the identity of the object i'm missing
21:03
<shu>
the implementation and security thing boils down to what i said in the explainer, that you want to be able to implement the first use case as not moving the underlying data pointer
21:03
<devsnek>
but if they *can* move
21:03
<shu>
if the underlying data pointer can move, you have perf cliffs, extra security risk to make sure you don't have stale data pointers, etc
21:04
<devsnek>
ah ok
21:04
<shu>
detaching was a huge security bug farm
21:04
<devsnek>
so its specifically, moving with the same object identity
21:04
<shu>
if you allow general data pointer moves, which is a much larger surface than "data pointer or null", it puts security folks on edge
21:04
<shu>
yep
21:05
<devsnek>
got it
21:05
<devsnek>
ok one other question
21:05
<shu>
shoot
21:05
<devsnek>
you mention the wasm detach problem in the motivation section
21:05
<devsnek>
about how you have to check every time you read if the buffer was detached
21:06
<devsnek>
is that solved with this? i didn't see anything but maybe i missed it
21:06
<shu>
good question, i didn't outline the solution in the explainer since. it's solved with the JS integration exposing a new API that uses growable buffers
21:07
<devsnek>
so its still on wasm to provide some sort of hook, ok
21:07
<shu>
no hook
21:07
<shu>
but right now, when you ask for a wasm memory, you get an AB back. i doubt that can be changed to return a ResizableAB and be web compat
21:07
<devsnek>
it couldn't be a resizableAB anyway
21:07
<devsnek>
wasm memories don't have to have an upper limit
21:08
<shu>
there can be a new API where the wasm JS api gives you a ResizableAB, which emscripten would use
21:08
<shu>
in practice there is, surely, set it at that
21:08
<devsnek>
i doubt most compilers emit an upper limit
21:08
<shu>
the emscripten team has told me this would solve their issue, at least
21:09
<shu>
i imagine not having a limit can be reported as like, 3gb when exposed to JS
21:09
<shu>
that can a contract for emscripten output, i imagine
21:09
<devsnek>
but then 3gb of your heap is reserved
21:10
<devsnek>
if you did that more than once in node you'd get an OOM
21:10
<shu>
that is not observable? and it also is in practice
21:11
<shu>
where possible wasm memory bounds checks are implemented with guard pages + segfault handler, and doing so reserves the virtual memory range
21:12
<shu>
perhaps you are confusing virtual memory reservation and getting them backed by physical memory
21:12
<devsnek>
if you make two reservations
21:12
<devsnek>
each 3gb or so
21:13
<shu>
if you are running the engine in 32bit, you've exhausted your vm range and are shit out of luck
21:13
<shu>
if you are running the engine in 64bit, you're probably fine
21:13
<devsnek>
but the v8 heap is only so large
21:13
<shu>
what do you mean by the v8 heap?
21:13
<shu>
the GC heap is not the process heap
21:13
<devsnek>
the place where all the stuff is stored
21:14
<shu>
there are several places :)
21:14
<devsnek>
the place where all the heap objects are stored
21:14
<shu>
buffer backing stores are not allocated on the GC heap
21:14
<devsnek>
oh
21:14
<devsnek>
interesting
21:14
<shu>
i don't think any engine does that?
21:15
<devsnek>
so they're just out in process memory?
21:15
<shu>
it's hookable by the embedder depending on where they need the buffer to be, but yes they're externally managed
21:15
<shu>
could be mmap'd directly
21:15
<devsnek>
interesting
21:15
<shu>
it's hard to get a contiguous address range otherwise
21:16
<devsnek>
i just figured most arraybuffers were usually small
21:16
<shu>
the GC heap can't be reserve contiguous gig+ ranges just in case an app needs it, for instance
21:16
<shu>
nope
21:16
<shu>
i think there's probably a bimodal distribution of buffer sizes
21:16
<shu>
given asmjs and wasm
21:16
<devsnek>
well wasm in itself is probably bimodal
21:17
<devsnek>
its either tiny canvas app or firefox running inside firefox
21:17
<devsnek>
anyway this is starting to make more sense
21:17
<shu>
thumbs up
21:17
<shu>
gotta run, bbl
21:18
<devsnek>
👋🏻
21:22
<Bakkot>
leobalter: I consume test262 in ~half a dozen projects and they will all need to be updated to point to main instead of master unless github supports redirecting branches, but I don't expect that to be all that much work
21:22
<leobalter>
Thanks Bakkot! Idk how to name it in that list so I'll have your name :)
21:22
<ljharb>
Bakkot: leobalter: iirc one thing you can do is point to "HEAD" and it'll always point to the default branch
21:23
<ljharb>
that's not the same as github supporting redirection for web URLs (which is still critically important) but it should suffice for tooling
21:23
<leobalter>
ljharb: too many thinks directly pointing to master
21:23
<leobalter>
in the import process
21:23
<leobalter>
or linking (which is worse)
21:27
<ljharb>
leobalter: what i mean is, the tools can all update from master to HEAD and they'll work moving forward, regardless of the default branch name (or the availability of an alternate name)
21:30
<leobalter>
FWIW is to set a plan to completely delete the master branch, so I need people to know we are doing this change
21:43
<rkirsling>
I think it might be better to lean harder on GitHub for updates on how soon they plan to deploy redirection
21:45
<ljharb>
i agree
23:48
<rkirsling>
so here's a question
23:48
<rkirsling>
if we're inclined to discouraging direct eval
23:48
<rkirsling>
how come we let it apply to lexical scopes too?
23:50
<rkirsling>
seems like some bud-nipping could've been done when introducing let/const
23:50
<Bakkot>
making direct eval do something more complicated than evaluate the code it's passed in the context it's in seems like it would be worse
23:50
<Bakkot>
at least the current state is possible to explain
23:51
<rkirsling>
hmm it's possible I haven't thought it through enough but
23:51
<rkirsling>
I was just thinking in terms of like
23:52
<rkirsling>
if vars hoist through blocks then it would seem like direct eval's visibility could be similarly scoped to the containing function
23:56
<rkirsling>
I mean I guess that would amount to creating a more awful thing just for the sake of discouraging its use though