18:42
<devsnek>
rickbutton: is there any info on RefCollection outside of that presentation
18:42
<devsnek>
because i have many many objections i'd like to write down
18:55
<rickbutton>
devsnek: yeah, there is a proposal repo, but it is currently private, msg-ing rricard to open it up
18:56
<devsnek>
removing ownership of refs from where they are contained seems like it automatically disqualifies the design tbh
18:56
<devsnek>
individual ref cells at each position would be better
18:56
<devsnek>
and better yet would be removing the restriction on objects in records
18:57
<rickbutton>
not sure what you mean by individual ref cells
18:57
<devsnek>
like instead of one thing owning a bunch of cells
18:57
<devsnek>
each instance is its own thing
18:57
<rickbutton>
oh i see
18:57
<rricard>
yea I can see that work as well
18:58
<devsnek>
but like i said
18:58
<devsnek>
better would be just allowing objects in records
18:58
<rickbutton>
what would it mean for a primitive to contain an object?
18:58
<rricard>
it's an early idea, I'm gonna try to get the RefCollection up asap
18:58
<devsnek>
it would mean there was a pointer to the object
18:58
<devsnek>
like how there will be pointers to the doubles
18:58
<devsnek>
because engines put doubles in the heap
18:58
<rickbutton>
well sure
18:59
<devsnek>
i don't understand your question then
18:59
<devsnek>
the record holds some keys and values
18:59
<devsnek>
why is there a limitation on the type of the value
18:59
<rricard>
Ergonomically there is a point in having to make the extra dereferencing hoo[
18:59
<rricard>
hoop*
18:59
<devsnek>
yeah the extra reference is kind of awful too
18:59
<devsnek>
even if you move to a per-instance cell
19:00
<rricard>
we can improve it
19:00
<rricard>
I agree it's annoying
19:00
<devsnek>
you could make the cell implicit in the record
19:00
<devsnek>
so you just do `#{ a: {} }`
19:00
<devsnek>
and then `whatever.a === that object`
19:00
<rickbutton>
one of the major arguments against objects in records is also an ergonomic one
19:01
<devsnek>
yeah people want to guarantee the objects are frozen all the way down
19:01
<rricard>
the ergonomic goal here is to typeerror
19:01
<rricard>
if you bail out, you have to explicitely do it
19:01
<rickbutton>
exactly, from our research most bugs introduced while using immutable libraries like Immutable.js and immer are at the boundaries
19:01
<rricard>
`#{ a: r({}) }
19:01
<devsnek>
from my perspective not allowing objects is unergonomic to the point of being a blocking point
19:01
<rricard>
whatever.a.deref() === that object
19:02
<rricard>
I don' t know but in this area
19:02
<devsnek>
so when two things collide i generally feel its better to go for the one that allows both
19:02
<devsnek>
allowing objects doesn't mean you can't have things that are immutable all the way down
19:02
<rricard>
I need to go for a quick while
19:03
<devsnek>
wasn't there a suggestion to have `##{}` or something which enforces immutable in its children
19:03
<devsnek>
or maybe ## was the one that allows mutable children
19:03
<devsnek>
i don't remember which was which
19:03
<rickbutton>
^ that question is why I'm not in favor of that syntax
19:03
<devsnek>
in either case
19:03
<devsnek>
not having objects directly seems like a huge pain point
19:03
<rickbutton>
allowing objects means that given a record you can't know if it is actually immutable
19:04
<devsnek>
like i'm imagining how i'd use these in node core
19:04
<devsnek>
and this would just be a huge pain
19:04
<devsnek>
to the point of not using them
19:05
<rickbutton>
do you have any specific examples? vv interested in them
19:05
<devsnek>
for example datagram packets
19:05
<devsnek>
to reply to a datagram message you need the host+port
19:06
<devsnek>
moving to `#{ host, port, socket }` would be cool
19:06
<devsnek>
except making socket a ref of some sort is a terrible api
19:06
<devsnek>
so i wouldn't bother
19:06
<devsnek>
or maybe `#{ host, port, socket, reply() }`
19:06
<devsnek>
except again you can't put the reply function in directly
19:07
<devsnek>
its like there's this cool feature but its so annoying to use its better to just not use it
19:08
<devsnek>
another example would be, if we supported evaluation results from TLA modules, they have to be packed up like { result: value }
19:08
<devsnek>
which seems like a good case for a record
19:08
<devsnek>
since mutating that would just cause confusion
19:08
<devsnek>
but if value happens to be an object that breaks
19:11
<rickbutton>
yes, allowing objects in records simplifies that use case, but on the other end, I think that allowing #[{}] !== #[{}] causes a significant amount of sharp edges in real world code, we find a majority of bugs in immutables happen because the user of the library didn't expect an object or doesn't understand object identity, so I worry that introducing a primitive that can deeply compare but won't if you aren't careful
19:11
<rickbutton>
is a super sharp edge
19:12
<devsnek>
do actual humans think of things in js as primitives and objects
19:12
<devsnek>
because i find that distinction pretty much meaningless
19:12
<rickbutton>
maybe not using the nouns "primitive" and "object" but certainly "things i can compare with ===" and "things i need to write a deep compare function for"
19:13
<rickbutton>
in the context of equality, at least
19:13
<devsnek>
so the problem is identity
19:13
<devsnek>
not the categorization
19:14
<rickbutton>
yeah exactly, the meat of the sharp edge is the fact that putting an object in a record implicitly gives the record identity
19:14
<devsnek>
i mean if they're defined to recursively have the identity of their parts (how most languages do it) then its not really a problem
19:14
<devsnek>
i guess you're saying people would be surprised that it stopped at the object boundary
19:15
<rickbutton>
yep, there is no spec reason it isn't possible, it's surprising for humans imo
19:15
<devsnek>
weird cuz i find it surprising the other way around
19:15
<rricard>
the main motivation we got on why it's like this is actually interviewing some developers using Immutable.js that ended up not trusting immutable equality because they started mixing object
19:15
<Bakkot>
my intuition exactly matches rickbutton's fwiw
19:16
<rricard>
that's a footgun we want to avoid
19:17
<devsnek>
if it was added without that behaviour i wouldn't find much use in it probably
19:17
<rricard>
making the ref hoop explicit is a way to at least bring awareness on that footgun
19:17
<devsnek>
so its hard to comment much on it at that point
19:17
<Bakkot>
devsnek: that seems fine; not every feature needs to be useful for everyone
19:17
<devsnek>
eh
19:17
<devsnek>
i mean if we're adding new primitives
19:17
<devsnek>
seems like a pretty high bar
19:17
<rickbutton>
(there is a balance, of course)
19:18
<Bakkot>
I would not find it useful if it allowed non-primitive objects, because of that sharp edge, so one of us is going to be out of luck
19:18
<Bakkot>
devsnek: oh, there is no way this would get through the committee if it was primitive and also allowed objects inside of it
19:18
<devsnek>
like private fields, i've probably used them like once ever because they're so limited
19:18
<Bakkot>
if it has objects inside of it, it is not primitive
19:18
<devsnek>
i don't want the same to happen to records
19:18
<devsnek>
because i think they're cool
19:19
<rickbutton>
if you don't want them to be primitives, what do you expect the behavior of === to be?
19:19
<rricard>
we're just starting on this, I'm sure we can find ways to make them useful
19:19
<rricard>
for you*
19:19
<devsnek>
on the subject of identity https://github.com/tc39/proposal-record-tuple/issues/65#issuecomment-606178554
19:19
<rricard>
refcollection is just a very basic way to do it so far
19:19
<devsnek>
i think the solution here is going to end up being some sort of new ref primitive
19:20
<devsnek>
and i'm just never going to use them
19:20
<Bakkot>
there is no way any sort of ref primitive is going to get through committee either
19:20
<rricard>
that's why symbol was a nice way to tie things up
19:20
<devsnek>
wait so then what is refcollection
19:20
<rricard>
but it has ergonomic issues
19:20
<devsnek>
oh it returns a symbol?
19:20
<rricard>
yes
19:20
<devsnek>
ah jeez
19:20
<Bakkot>
that's kind of cute
19:20
<rricard>
yes reakized my slides suck
19:21
<devsnek>
that seems like a huge footgun too
19:21
<devsnek>
nothing implies its a ref to another object in that case
19:21
<devsnek>
you have to implicitly know
19:21
<rricard>
the refcollection is there to make you manage it
19:21
<devsnek>
no like
19:21
<devsnek>
if i hand you a record
19:21
<devsnek>
you have to know
19:21
<devsnek>
exactly where all those symbols are
19:22
<rricard>
I agree it's not perfect
19:22
<devsnek>
and that they need to be unwrapped
19:22
<devsnek>
and you have to be given the refcollection somehow
19:22
<devsnek>
out of band
19:22
<rickbutton>
if you hand me a record, you also need to hand me a refcollection
19:22
<devsnek>
why not just hand you an object then
19:22
<devsnek>
like if Object.freeze is easier
19:23
<devsnek>
i end up never using this
19:23
<rricard>
the most primitive form of that is I hand you an object with the record and the symbol mapping
19:23
<rickbutton>
with Object.freeze you lose deep equality checks
19:24
<devsnek>
there are deep equality libraries 🤷🏻
19:25
<Bakkot>
devsnek: stepping back a bit, why do you want to have these records-with-mutable-contents?
19:25
<devsnek>
i gave some examples above
19:25
<Bakkot>
you said you wanted to write `#{ host, port, socket }`, but I don't know why you want to write that
19:25
<devsnek>
i think there are more use cases for records than diffing react trees
19:26
<devsnek>
right because those shouldn't be mutable
19:26
<rricard>
we also discussed with jridsgewell about template-records and tuples
19:26
<devsnek>
and that also means you can compare the two message origins
19:26
<devsnek>
with ===
19:26
<rricard>
jridgewell*
19:26
<devsnek>
instead of doing a.host === b.host && a.port === b.port && a.socket === b.socket
19:26
<devsnek>
yeah template records make zero sense to me
19:26
<devsnek>
template tuples maybe
19:27
<Bakkot>
devsnek: what's the advantage of them not being mutable? are you handing the same object off to multiple parties somewhere?
19:27
<devsnek>
Bakkot: they're part of the public node api
19:27
<devsnek>
if you mutated them all you're doing is creating confusion
19:27
<Bakkot>
devsnek right my question is, does the API return the same object to multiple different callers, or does it make a fresh object for each caller?
19:28
<Bakkot>
because if it's fresh, I don't see much advantage in immutability
19:28
<devsnek>
i mean if you just don't think this is a valid use case then whatever
19:28
<Bakkot>
no I am just trying to understand why you want this
19:28
<Bakkot>
for context, to me the advantage of immutability is mostly when you have one object you're handing to multiple parties, so that one party cannot mutate it and thereby mess up the other party
19:29
<devsnek>
immutability is whatever
19:29
<devsnek>
the main reason in this case is equality and being able to use it as a map key or something
19:29
<Bakkot>
ahh
19:30
<devsnek>
i really hope tuples can replace Symbol.compositeKey
19:30
<devsnek>
but you just end up with huge leaks if you use ref cells
19:31
<devsnek>
well refcollection cells
19:31
<Bakkot>
the map key thing I tend to just solve in userland, but it does get a bit awkward
19:31
<Bakkot>
I should clean up the library I wrote for that and publish it maybe
19:31
<rickbutton>
how do you end up with leaks?
19:31
<Bakkot>
ends up being pretty clean for users, just messy internally
19:31
<devsnek>
RefCollection has to strongly reference the object
19:31
<devsnek>
as long as the symbol could possibly be alive
19:31
<devsnek>
and since userland can't iterate over the heap
19:32
<devsnek>
we just have to call that forever
19:32
<rricard>
the refcollection polyfill will leak until it's released
19:32
<devsnek>
yeah so
19:32
<devsnek>
not good for maps
19:33
<rricard>
but you can see an implementation in engine where it automatically releases
19:33
<devsnek>
the map implementation can't tell if the object is still being used from the symbol it has
19:33
<devsnek>
you can clean the entire map
19:33
<devsnek>
but not individual keys
19:33
<devsnek>
individual entries
19:33
<rricard>
yes I agree in the case of the polyfill
19:34
<rickbutton>
well, you can use a FinalizationRegistry
19:34
<devsnek>
i guess you could
19:34
<rickbutton>
but an in-engine impl can handle that of course
19:34
<devsnek>
that seems incredibly complex for the simple case of compound keys
19:34
<rickbutton>
I don't see where RefCollection comes into play for compound keys
19:35
<devsnek>
because the keys could be objects
19:35
<rricard>
ultimately if this works for a unique refcollection we can think of a more global mechanism
19:35
<devsnek>
maps can use objects as keys
19:36
<rickbutton>
oh I see, you are saying if records allowed objects via RefCollection then records-as-keys-in-Map gets more weird if the records include objects
19:36
<devsnek>
i just want there to be more use to this than react vdoms
19:37
<devsnek>
without super contrived apis
19:38
<devsnek>
if the object thing can't be worked out, perhaps the equality can be split into a separate syntax
19:38
<devsnek>
#@{} for immutable+deeply equal or something
19:38
<devsnek>
though immutability with implicit object refs is nice :(
19:43
<rickbutton>
to be fair none of our internal research involves using record&tuple for vdoms, they just provide a consise and well-understood example (they would obviously be beneficial though)
19:43
<devsnek>
i'm just thinking of all the things i do with PartialEq in rust
19:43
<Bakkot>
yeah, I confess have also (almost) never used react vdoms
19:44
<devsnek>
all the examples i've seen so far involve vdoms
19:44
<devsnek>
not inherently react i guess
19:44
<Bakkot>
or any other vdoms
19:44
<ljharb>
tbh i'm still not clear on why having first class refs in the language would not be a terrible thing
19:45
<devsnek>
yeah i'd probably block if symbols in global caches was the solution
19:45
<ljharb>
like, i've seen a couple use cases for them, but nothing compelling to me
19:45
<devsnek>
(not block as in tc39 block)
19:45
<ljharb>
and i've always considered it a wonderful thing that JS doesn't have refs/pointers
19:46
<devsnek>
symbols seem strictly worse imo
19:46
<devsnek>
in this use case
19:54
<bradleymeck>
well i missed some talking
19:55
<devsnek>
lol
19:55
<rickbutton>
hahaha
19:55
<rickbutton>
I'm on day 22 of isolation if I don't argue semantics then I can't tell if I'm alive
19:56
<devsnek>
its mostly just me having private symbol deja vu with records
20:00
<jmdyck>
I argue therefore I am.
20:01
<ljharb>
nuh uh
20:02
<bradleymeck>
i doubt compositeKey could be replaced as long as things strongly hold onto refs
20:03
<devsnek>
that's my fear
20:04
<bradleymeck>
why does it have to replace compositeKey?
20:04
<devsnek>
it doesn't have to
20:04
<devsnek>
but it is kind of an easy step to take
20:04
<bradleymeck>
i don't see how it is easy? since these are strong refs
20:04
<devsnek>
since they have the identity of their children
20:05
<devsnek>
no I mean if they didn't require all the ref stuff
20:05
<bradleymeck>
kind of?
20:05
<bradleymeck>
compositeKey allows partial GC idk how this would
20:05
<devsnek>
it does what
20:06
<bradleymeck>
compositeKey(a, b, c) lets b GC regardless of if the key lives
20:06
<devsnek>
weird
20:06
<bradleymeck>
a, b, and c do not have their lifetimes interwoven nor tied to the key
20:07
<devsnek>
I mean that makes sense in some ways
20:07
<devsnek>
I think this is just the problem of having a weird symbol wrapper
20:07
<bradleymeck>
you just won't be able to reproduce the key from them (since b is gone)
20:07
<devsnek>
it's a contrived solution
20:07
<bradleymeck>
how so?
20:07
<devsnek>
you're making a weird function that does magic with objects to create some symbol
20:07
<bradleymeck>
its not magic, just some weakmaps
20:08
<devsnek>
Vs just using the inherent identity rules of the language
20:09
<devsnek>
yeah I know how it works internally, I mean it's not obvious or natural
20:09
<bradleymeck>
rickbutton: rricard it might be interesting to compare the RC to compositeKey in general. compositeKey explicitly doesn't have a way to reflect on component parts
20:09
<devsnek>
in languages with tuples like rust and python you just naturally use them as map keys
20:09
<devsnek>
bevause it makes sense
20:09
<bradleymeck>
devsnek: it seems fine for me coming from the perspective of DBs with composite keys
20:10
<bradleymeck>
you could use things as a map key in those languages but they stay strongly held
20:10
<bradleymeck>
which is part of the point of not doing that in the compositeKey proposal
20:10
<devsnek>
yeah I mean it's not crazy
20:10
<devsnek>
I'm fine with composite key
20:11
<devsnek>
but given we might have tuples
20:11
<devsnek>
those would be way more natural
20:12
<devsnek>
if you needed the weakmap semantics you'd usually do that yourself
20:12
<devsnek>
also various things about whether you want it to drop from the map or not
20:12
<bradleymeck>
you could have both but you would want to lean towards compositeKey for anything with differing lifetimes if memory is a premium, also you can't weakmap tuples so that makes things hard to deal with in a weak way
20:12
<devsnek>
there are a lot of options there that the language can't infer for you
20:12
<bradleymeck>
i'd agree but i wouldn't say tuples replace arrays or weak keys
20:12
<Bakkot>
map can't have it drop; it would have to be weakmap
20:13
<Bakkot>
and a weakmap could drop it iff the key itself was dropped and all its values were
20:13
<Bakkot>
that one I think the language can infer
20:13
<bradleymeck>
Bakkot: but that requires the key to drop before its components can gc is my point
20:14
<bradleymeck>
so you have interwoven the lifetimes
20:14
<Bakkot>
bradleymeck wait, why does it?
20:14
<devsnek>
you'd use finalization registry to make it drop
20:14
<Bakkot>
I am not suggesting you can use the composite to get its components
20:14
<bradleymeck>
Bakkot: if you can get the key you can access the components
20:15
<devsnek>
even if the objects are dead, because you hold that unique symbol
20:15
<Bakkot>
in your proposal? that is not required to be true for the thing I said
20:16
<bradleymeck>
Bakkot: in my proposal that isn't true, but i thought your antecedent was about tuples
20:16
<Bakkot>
ah
20:16
<Bakkot>
no, was speaking of composite keys, sorry
20:17
<devsnek>
my overarching point was that weird behaviour like interactions with object lifetimes should be explicit because you're probably doing something that is a special case
20:17
<Bakkot>
for composite keys, map cannot drop the key ever because maps cannot drop anything, and for weakmaps the key can be dropped if the key itself and at least one of its components has been dropped
20:18
<devsnek>
you can't use a composite key in a weakmap
20:18
<devsnek>
it's just a symbol
20:18
<bradleymeck>
you can in the object form
20:18
<devsnek>
there's an object form?
20:19
<bradleymeck>
it has object and symbol, symbol was only added because people wanted it
20:19
<devsnek>
interesting
20:19
<devsnek>
I wish weakmaps could hold symbols
20:19
<bradleymeck>
you can recreate compositeSymbol easily enough and people wanted it so 🤷
20:19
<ljharb>
they can hold boxed symbols
20:20
<devsnek>
ljharb: not that helpful though
21:45
<ljharb>
does anyone know where to report that w3 has uncool URLs? https://www.w3.org/TR/wai-aria/roles no longer works
21:45
<ljharb>
(and a bunch of others)
21:51
<devsnek>
what is /roles supposed to be
21:53
<ljharb>
specifically, https://www.w3.org/TR/wai-aria/roles#composite_header 404s and the content now lives at https://www.w3.org/TR/wai-aria/#composite
21:53
<ljharb>
also https://www.w3.org/TR/wai-aria/states_and_propertieshttps://www.w3.org/TR/wai-aria/#states_and_properties
21:54
<ljharb>
and a few others
21:54
<ljharb>
basically it looks like they regressed their site back to hashbang URLs, like it's 2006
21:54
<ljharb>
the main thing is that they need to add redirects, but i'm not sure where to report that
22:15
<jridgewell>
Late to the R&T discussion, but
22:15
<jridgewell>
> my intuition exactly matches rickbutton's fwiw
22:15
<jridgewell>
Same here. I really like this new design.
22:15
<devsnek>
😢
22:23
<jridgewell>
And I also don't understand how tuples could have replaced CompositeKeys
22:23
<jridgewell>
Even the old design
22:24
<jridgewell>
Would have caused a permanent memory leak, ala the tagged template literal redesign
22:24
<jridgewell>
As soon as you stick the old Tuple into a WeakMap, it becomes a permanent value
22:25
<devsnek>
if you have the tuple you have the key
22:25
<devsnek>
if you don't you don't
22:25
<devsnek>
i agree the semantics on how to release them is iffy
22:27
<jridgewell>
The problem is that I could create the key at any future point
22:27
<jridgewell>
So that key can never be released
22:27
<devsnek>
right as long as the objects exist
22:27
<devsnek>
that isn't surprising to me
22:28
<jridgewell>
Consider it without the objects, purely immutable primitive types
22:28
<devsnek>
you can't put that in a weakmap
22:28
<jridgewell>
If I did `weakMap.set([1, 2, 3], {})`
22:29
<devsnek>
you can't use numbers as weakmap keys though
22:29
<jridgewell>
Sorry, meant `weakMap.set(#[1, 2, 3], {})`
22:29
<devsnek>
you still can't use numbers as weakmap keys
22:29
<jridgewell>
It's a tuple, though
22:29
<jridgewell>
Which is just an immutable array
22:29
<devsnek>
tuple of numbers
22:30
<jridgewell>
Tuple of _anything_ is my point
22:30
<devsnek>
there has to be a lifetime somewhere for it to be valid as a weakmap key
22:30
<devsnek>
(i probably wouldn't use tuples in weakmaps in either case)
22:30
<jridgewell>
I don't think that's going to fly with end users
22:30
<jridgewell>
"Why is this tuple allowed and not that one?"
22:30
<devsnek>
#[1, 2, 3] as a weakmap key is nonsensical
22:31
<devsnek>
the same way 5 as a weakmap key is nonsensitcal
22:31
<devsnek>
nonsensical
22:31
<jridgewell>
The difficulty is explaining this to anyone
22:31
<jridgewell>
I can say the same about `Symbol('foo')` and `Symbol.for('foo')`
22:31
<jridgewell>
Why would one be allowed and the other now?
22:31
<jridgewell>
Why would one be allowed and the other not**?
22:31
<devsnek>
neither are allowed atm
22:32
<jridgewell>
Wasn't that just discussed above?
22:32
<devsnek>
i don't think its worth trying to argue about the behaviour of values based on weakmap keys
22:32
<devsnek>
because everything is very weird
22:33
<jridgewell>
But this is a discussion on replacing CompositeKey with R&T, which has to work for maps and weakmaps.
22:33
<jridgewell>
I don't think there's we can discuss one without the other.
22:34
<devsnek>
i wasn't really thinking about weakmaps
22:34
<jridgewell>
Only maps?
22:35
<devsnek>
yes, i don't think its bad that you have to build your own keying system for weakmaps
22:35
<devsnek>
the lifetimes there are tricky to get right and if any of it is done implicitly you might accidentally leak something
22:35
<devsnek>
or end something too early
22:36
<jridgewell>
For maps only, I think either R&T design would work?
22:36
<devsnek>
what is r&t
22:36
<jridgewell>
Records & Tuples
22:36
<devsnek>
by either design do you mean with or without objects allowed?
22:37
<jridgewell>
Yah, if I've skimmed the above discussion correctly
22:37
<jridgewell>
One with `Ref`, and one with direct mutable objectcs
22:37
<devsnek>
i think it would be pretty useless without objects allowed
22:38
<devsnek>
you have to set up really a bunch of lifetime management with the ref stuff
22:38
<devsnek>
even though you don't care about lifetimes at all
22:38
<devsnek>
and ref has a lot of other problems
22:38
<jridgewell>
I guess it couldn't be just a second tuple to let it handle for you.
22:39
<devsnek>
i'd be fine with two kinds of tuples
22:39
<jridgewell>
Eg, `Map.set(#[ immutable, refs ])`, where you get the immutable and refs from the first R&T.
22:39
<jridgewell>
Because the `refs` reference wouldn't be allowed.
22:40
<devsnek>
i don't understand what this means
22:40
<jridgewell>
Bradley's `CompositeKey` might work
22:40
<jridgewell>
It's an attempt to store both the tuple and it's mutable refs in a single Map key.
22:40
<devsnek>
that doesn't seem possible
22:40
<jridgewell>
So you don't manually manage the lifetime of the refs, it's done for you
22:41
<devsnek>
given just the objects that make up the key
22:41
<devsnek>
where do you derive the refs from
22:41
<devsnek>
for a get() operation
22:42
<devsnek>
on a larger level this is the problem, if you just allow objects you don't have to solve all these problems because the semantics just naturally work together
22:43
<devsnek>
but apparently that's also a footgun
22:43
<devsnek>
(i never encountered that being a problem in python though)
22:46
<jridgewell>
Is `refs` not a map itself?
22:46
<jridgewell>
So it holds onto the mutable objects?
22:47
<devsnek>
you're the one who brought refs into this
22:48
<devsnek>
in order to get an item out of the map you need to have the identity with it, so you'd need a reference to `refs`
22:48
<devsnek>
i'm not sure what `refs` is though
22:48
<devsnek>
is it the RefCollection?
22:48
<jridgewell>
Yah
22:49
<jridgewell>
`const refs = new RefCollection();`
22:49
<devsnek>
well you can't store that in a tuple
22:49
<devsnek>
since its an object
22:49
<jridgewell>
I see it uses `deref`
22:49
<jridgewell>
Instead of `get`
22:49
<devsnek>
RefCollection.prototype.ref apparently returns a symbol
22:50
<jridgewell>
Yah
22:50
<devsnek>
so you just have to know that some symbols in records and tuples need to be derefed in some random refcollection somewhere
22:50
<devsnek>
which refcollection? who knows!
22:50
<jridgewell>
This is the same as with Tagged Template Literals
22:50
<devsnek>
in what way
22:51
<jridgewell>
Mutable data is stored out-of-band (in the invocations arguments)
22:51
<jridgewell>
And immutable data is stored as a frozen `TemplateStringsArray`
22:51
<jridgewell>
You reference the mutable data based on the index
22:51
<devsnek>
is it frozen?
22:51
<jridgewell>
Is what frozen?
22:51
<devsnek>
the array
22:51
<devsnek>
i know its cached
22:52
<jridgewell>
The `TemplateStringsArray` is frozen
22:52
<jridgewell>
The arguments aren't frozen, you have to generate your own array
22:52
<devsnek>
yeah
22:52
<devsnek>
i'm not seeing how this relates to map keys though
22:53
<devsnek>
are you saying you want to have a key that is the template string array and the values together
22:53
<devsnek>
for caching the rendered result or something
22:57
<jridgewell>
No, I was talking about using a Tuple for CompositeKey still
22:57
<jridgewell>
But it doesn't work it still doesn't work.
22:57
<jridgewell>
CompositeKey would, though
22:57
<jridgewell>
You'd just stick your immutable R&T and the mutable Refs into a CompositeKey, and let the `===` take care of the equality
22:58
<devsnek>
where do you get refs from
22:58
<devsnek>
for get()
23:00
<jridgewell>
https://button.dev/talks/record-and-tuple-tc39-march-2020.pdf https://www.irccloud.com/pastebin/CWoXdvIl/RefCollection.js
23:00
<jridgewell>
`rc` is a brand instance you make with every tuple
23:00
<jridgewell>
(`rc` being what I was calling `refs`)
23:01
<devsnek>
yeah i've seen the slides
23:07
<jridgewell>
With the Tagged form of R&T, you'll could get them automatically as a parameter
23:08
<jridgewell>
We'd just have to settle on a syntax for Tagged form and inclusions.
23:08
<devsnek>
jridgewell: i'm still not convinced that tagged records and tuples make any amount of sense
23:09
<devsnek>
its like saying tagged object literal or tagged array literal
23:10
<jridgewell>
You had a very real complaint about the burden of creating a `RefCollection`
23:10
<jridgewell>
It just solves that for you
23:11
<devsnek>
i don't understand how it does anything
23:11
<devsnek>
it doesn't make sense to me
23:14
<jridgewell>
`tag#{ foo: object }` would invoke `foo` with an already built record and refs
23:14
<devsnek>
`tag#{}` doesn't make sense to me
23:14
<jridgewell>
So you wouldn't have to create and do the `rc.ref(...)` manually
23:14
<devsnek>
regardless of what {} contains
23:14
<devsnek>
and that doesn't solve the ref problem
23:15
<jridgewell>
Did ``` tag`x` ``` make sense at first?
23:15
<devsnek>
yes
23:15
<jridgewell>
Why?
23:15
<devsnek>
but i literally cannot figure out what semantics `tag#{}` has
23:15
<devsnek>
it feels like you're saying tagged number
23:15
<devsnek>
actually i can think of things that tagged numbers would do
23:16
<devsnek>
the best i can come up with is something analogous to the JSON.stringify callback for a "tagged record"
23:16
<devsnek>
but that seems like a reach
23:19
<ljharb>
it does look kind of weird, `tag#`
23:19
<jridgewell>
https://www.irccloud.com/pastebin/Ub13FBLx/
23:19
<ljharb>
like at least `obj.#x` has the `.` in it
23:19
<devsnek>
oh you're saying `tag#{}` is shorthand for proper records that allow all values in them
23:19
<jridgewell>
Yes
23:19
<devsnek>
there are a lot of problems with that
23:19
<devsnek>
for example
23:19
<jridgewell>
Because the values will be put into the refs automatically
23:20
<devsnek>
`tag1#{ x: tag2#{ y: {} } }`
23:20
<jridgewell>
What's wrong with that?
23:20
<devsnek>
having separate refs just don't work
23:20
<jridgewell>
We do the same with tagged templates
23:20
<devsnek>
you lose the refs in x
23:20
<jridgewell>
You have to return a result from the tag
23:20
<jridgewell>
If you want to use a result
23:21
<devsnek>
what could the possible return value be
23:21
<devsnek>
to be useful
23:21
<jridgewell>
https://github.com/polymer/lit-html/
23:21
<devsnek>
like if i just want records that can hold objects
23:21
<jridgewell>
The entire design of Tagged Template Literals is about the return value
23:21
<jridgewell>
Lit uses `TemplateResult` values
23:21
<jridgewell>
Which allow you to render
23:21
<devsnek>
yes but we're not trying to compose the values of a record
23:22
<devsnek>
they're already composed
23:22
<devsnek>
into key: value
23:22
<jridgewell>
But they're not, because you can't hold mutable values.
23:22
<devsnek>
right
23:22
<devsnek>
so you end up
23:22
<devsnek>
with this useless function
23:22
<jridgewell>
You need a tag that actually does something
23:22
<devsnek>
what is "something"
23:22
<devsnek>
what possible use is there
23:23
<jridgewell>
https://github.com/Polymer/lit-html/blob/master/src/lit-html.ts#L67-L68
23:23
<jridgewell>
https://github.com/Polymer/lit-html/blob/7c7442278281a6923eb1dfbb77600b8b64522a50/src/lit-html.ts#L67-L68
23:23
<jridgewell>
You return a value that composes the immutable and mutable parts
23:23
<devsnek>
they're already composed
23:24
<jridgewell>
And do something with that value in your library
23:24
<devsnek>
into keys and values
23:24
<jridgewell>
They are not by definition.
23:24
<devsnek>
if you don't want that
23:24
<devsnek>
why are you using a key value thing
23:24
<jridgewell>
You cannot hold mutable data in an immutable record
23:24
<devsnek>
this doesn't solve the problem
23:24
<jridgewell>
So, no, they are not composed.
23:25
<devsnek>
i started with mutable and immutable components that can't be composed
23:25
<devsnek>
and ended with mutable and immutable components that can't be composed
23:26
<devsnek>
because they're still stuck in a record and a floaty "refs" object
23:26
<devsnek>
the refs can't be associated with the record in any way
23:26
<devsnek>
and if you want nested structures
23:26
<devsnek>
you can't put refs anywhere
23:26
<devsnek>
because again its an object
23:27
<devsnek>
and refs really fall apart as soon as you start combining records and tuples from different places
23:28
<devsnek>
have like five different ref collections each holding a different bit of this tuple i'm trying to get values out of
23:28
<devsnek>
does accessing a value become O(n) to the number of ref collections since you have to check each one
23:29
<devsnek>
where do you even put all these ref collections
23:29
<jridgewell>
https://www.irccloud.com/pastebin/84lzR9OW/deep-tagged-record.js
23:30
<jridgewell>
This is entirely up to the tag library
23:30
<jridgewell>
And it's the _same_ super powers we give to Tagged Template Literals
23:30
<devsnek>
so in this case
23:31
<devsnek>
you nest the refs deeply
23:31
<devsnek>
refs.get(refs).refs.get(refs)
23:31
<jridgewell>
As example code, yes.
23:31
<jridgewell>
Again, the tag library can do anything.
23:31
<devsnek>
can it solve this problem in a reasonable way?
23:32
<devsnek>
refs.get(refs).refs.get(refs) doesn't seem to pass the bar for in-the-language design
23:35
<jridgewell>
https://www.irccloud.com/pastebin/WqdrIhyA/deep-tagged-template-literals.js
23:35
<devsnek>
obviously yes
23:36
<jridgewell>
Is this any different than^
23:36
<devsnek>
tagged templates flatten into one value
23:36
<devsnek>
records flatten into two values
23:36
<jridgewell>
How?
23:36
<devsnek>
because tagged templates are allowed to return objects that reference objects
23:36
<jridgewell>
Because if you flatten it all into a single object, you lose the positions of the interpolations
23:37
<jridgewell>
Which means it was no better than constructing the object in the first place.
23:37
<devsnek>
i'm just really not sure what problem tagged records solve
23:37
<devsnek>
i guess it makes making vdoms easier
23:37
<devsnek>
it doesn't solve my problem though
23:38
<jridgewell>
I don't think your problem can be solved while giving interpolation positions.
23:38
<devsnek>
i don't think my problem can be solved by tagged records
23:38
<devsnek>
period end of story
23:38
<jridgewell>
Which would limit the use of records in any tree structure
23:39
<jridgewell>
vdom just being one use case.
23:39
<devsnek>
as far as i can tell i would not have any use cases for records and tuples
23:39
<devsnek>
with the current design
23:39
<devsnek>
they just wouldn't be usable
23:40
<devsnek>
and its giving me private fields vibes (i have no uses for those either because they're so limited)
23:40
<jridgewell>
As a counter, I don't think mixing mutable and immutable in the same structure solve any real problem.
23:40
<jridgewell>
It's just a mutable structure then.
23:40
<devsnek>
immutable isn't the only thing that records and tuples have
23:40
<devsnek>
their identity is the identity of their children
23:41
<devsnek>
which is useful in lots of cases
23:41
<devsnek>
even if the structure is mutable
23:41
<jridgewell>
Which would be broken with any mutable reference
23:41
<devsnek>
i'm not diffing vdoms
23:42
<devsnek>
i gave an example above of a udp datagram origin object
23:42
<jridgewell>
How would you generate a second UDP packet that's equal?
23:43
<devsnek>
its not the packet data
23:43
<devsnek>
its the origin of the packet
23:43
<devsnek>
the ip and port
23:43
<jridgewell>
s/packet/datagram/
23:43
<devsnek>
you need both to reply
23:43
<devsnek>
but you also don't want to combine them into a string or something because then you have to parse it apart
23:44
<jridgewell>
There are no problems with 2 primitives in a tuple, though.
23:44
<devsnek>
(notice that composite keys also don't work here because they don't ref the items that they're made of)
23:44
<devsnek>
yes but then maybe you want to add the socket reference
23:45
<devsnek>
anyway if this comes down to my use cases not being valid there's not much point in arguing
23:46
<jridgewell>
What socket reference?
23:46
<devsnek>
on a high level, node has a datagram socket instance
23:48
<devsnek>
you could also do a reply function right on the origin record
23:49
<devsnek>
though the semantics of the identity of that would be iffy
23:53
<jridgewell>
What if we had operator overloading?
23:54
<jridgewell>
Eg, my deep equality tag returns some instance that will do equality for you.
23:54
<devsnek>
i don't need deep equality of normal objects
23:54
<jridgewell>
Or, just a `Datagram` class that had equality without even involving R&t.
23:54
<devsnek>
oh i see what you mean
23:55
<devsnek>
on a very theoretical level that would work
23:55
<devsnek>
but i don't think operator overloading is a good idea in js
23:56
<devsnek>
afaik it has yet to be shown that you can do it in an ergonomic way without slowing down all occurrences of the overloaded operator
23:56
<jridgewell>
Even the static import design?
23:56
<jridgewell>
I thought that solved the issue.
23:56
<devsnek>
the `with operators` thing?
23:56
<jridgewell>
Yah
23:56
<devsnek>
i don't consider that ergonomic
23:57
<devsnek>
honestly i think its more of a footgun
23:57
<devsnek>
since you can just forget to have it
23:57
<devsnek>
especially the more you scope it
23:57
<devsnek>
the more you need it
23:57
<devsnek>
the more places you can forget it
23:57
<ljharb>
that's the first design that i don't instantly and violently abhor
23:57
<ljharb>
but i'm not convinced either
23:57
<devsnek>
it's not as bad as others
23:58
<devsnek>
but i don't think it's good enough
23:58
<devsnek>
i also have issues with how static it is