00:01 | <ljharb> | like thenability is forgeable, instanceof is forgeable, brand checks are not |
00:04 | <ljharb> | iow identity is indeed unforgeable for objects and symbols, but forgeability goes way beyond just identity to me |
00:04 | <Bakkot> | webidl has a definition of "unforgeable", which applies to attributes: https://heycam.github.io/webidl/#dfn-unforgeable-on-an-interface |
00:14 | <devsnek> | ljharb: hm I guess it applies in a lot of situations |
00:16 | <devsnek> | in regard to values, it means you can't create a value with the same identity, you have to have the actual value to have the same identity |
00:17 | <devsnek> | which is the distinction we're using for weak collection keys |
00:21 | <Bakkot> | devsnek except the current proposal allows `Symbol.for` symbols, I think |
00:21 | <devsnek> | those are still unforgeable |
00:22 | <Bakkot> | not any more unforgeable than string literals, surely? |
00:22 | <devsnek> | symbol.for doesn't create new values, there's a cache |
00:22 | <Bakkot> | I don't understand the distinction between Symbol.for symbols and strings |
00:22 | <Bakkot> | what is the relevant distinction here? |
00:22 | <devsnek> | you can create caches of objects too |
00:23 | <Bakkot> | ... so? |
00:23 | <devsnek> | I mean from some level of abstraction nothing is unforgeable because you can store it in something keyed by strings |
00:23 | <Bakkot> | neither Symbol.for symbols nor strings are objects |
00:23 | <Bakkot> | I don't see what the distinction between those two things is |
00:24 | <Bakkot> | I get splitting out objects from non-Symbol.for symbols: there if you don't already have access to the thing, possibly transitively (via a cache or whatever), you cannot get it |
00:24 | <Bakkot> | but this is not true for Symbol.for symbols or for strings |
00:24 | <Bakkot> | those you can synthesize in a new realm without access to anything outside of the realm |
00:25 | <devsnek> | but the symbols in the agent cache aren't being forged, they're just normal symbols |
00:25 | <Bakkot> | I don't know what you mean by forged |
00:25 | <Bakkot> | the point of this conversation is to try to get at what you mean by forged |
00:26 | <devsnek> | a new value is created with the identity of some other value |
00:26 | <Bakkot> | I don't know what it means to be a "new value" but have the identity of another value |
00:26 | <Bakkot> | that seems like it is tautologically impossible |
00:26 | <devsnek> | like two strings both containing the same characters in the same order |
00:27 | <Bakkot> | how is that any more of a new value than a Symbol.for symbol is? |
00:28 | <devsnek> | because symbol.for doesn't always return a new symbol |
00:28 | <Bakkot> | neither does writing a string literal |
00:28 | <devsnek> | it definitely does |
00:29 | <Bakkot> | maybe in your implementation, not in mine |
00:29 | <Bakkot> | the difference is not observable to user code |
00:29 | <devsnek> | I'm not sure what optimization has to do with this |
00:29 | <Bakkot> | you're the one who brought it up? |
00:30 | <devsnek> | no I didn't |
00:30 | <Bakkot> | you said "symbol.for doesn't always return a new symbol". this is exactly as true as "writing a string literal doesn't always return a new string". |
00:31 | <devsnek> | no symbol.for is specified to not always return a new symbol |
00:31 | <Bakkot> | string literals are not specified to return new values either |
00:31 | <Bakkot> | the spec in fact speaks of "the" empty string |
00:32 | <devsnek> | I'm not sure what we're talking about anymore |
00:32 | <devsnek> | my point was being able to cache a type doesn't make it a forgeable type |
00:33 | <Bakkot> | I'm trying to understand what distinction you see between Symbol.for symbols and string literals, from the perspective of, only the former is "forgeable" |
00:33 | <devsnek> | symbol.for symbols are symbols |
00:33 | <devsnek> | we only have one kind of symbol in js |
00:34 | <Bakkot> | depending on what you mean by "kind", sure |
00:34 | <Bakkot> | but this does not help me understand what you mean by "forgeable" |
00:35 | <Bakkot> | all objects, and symbols not created by Symbol.for, have the property that code running in a fresh realm cannot get access to them. but this is not true of symbols created by Symbol.for, just as it is not true of string literals. so clearly this cannot be the definition of "forgeable". |
00:35 | <devsnek> | forgeable = you can create a value that has the identity of another value without having access to the original value |
00:36 | <Bakkot> | ok, so, in what way are Symbol.for symbols not forgeable? |
00:36 | <devsnek> | you have to look up the original value using Symbol.for |
00:37 | <devsnek> | you can't produce it out of thin air |
00:37 | <Bakkot> | Symbol.for is thin air |
00:37 | <Bakkot> | it exists in fresh realms; it does not need to be passed in |
00:37 | <devsnek> | that's what i meant above |
00:37 | <devsnek> | "I mean from some level of abstraction nothing is unforgeable because you can store it in something keyed by strings" |
00:39 | <Bakkot> | you can't store it in a way which will be available to code with which you share no communication channel |
00:39 | <Bakkot> | i.e. you have to actually pass the value, or a thing which has access to the value, to the new code |
00:39 | <Bakkot> | i.e. it can't make it itself |
00:39 | <Bakkot> | this is not true of Symbol.for symbols |
00:39 | <devsnek> | for mark's definition of communication channel sure |
00:41 | <Bakkot> | for any definition of communication channel |
00:42 | <devsnek> | sure |
00:43 | <devsnek> | i would just say the globals are passed to the realm and therefore the symbol is passed to the realm |
00:47 | <bradleymeck> | Bakkot: i think the crux of this is just that you cannot recreate the value with undeniable computation / primitive computation |
00:49 | <bradleymeck> | basically the idea is since you can censor `.for` using APIs but cannot censor things like 'it'+'erator' |
07:02 | <bendtherules> | Hi all! |
07:02 | <bendtherules> | I am having a little problem understanding why - AssignmentRestProperty doesn't allow Array or Object Literal inside it, but AssignmentRestElement allows them |
07:02 | <bendtherules> | So, I can write `[a, ...{0: b, length: c}] = [1,2,3,4,5]` but not `({a, ...{b}} = {a: 1, b: 2})` |
07:02 | <bendtherules> | What is the reason for allowing destructuring after ... in array destructuring, but not in object dest.? |
07:04 | <bendtherules> | This is the relevant spec link - https://tc39.es/ecma262/#sec-destructuring-assignment-static-semantics-early-errors |
07:04 | <ljharb> | bendtherules: the former is gathering the first item in `a` and the rest in an array, that you're destructuring |
07:04 | <ljharb> | bendtherules: i can see why you'd think the latter is allowed, but it seems nonsensical to me since you can just remove the `...{ }` |
07:05 | <bendtherules> | True, but then what is the rational behind allowing `[a, ...[b, c]] = []`? |
07:06 | <bendtherules> | Array literals seem to allow both obj. and array dest, after ... |
07:06 | <ljharb> | i'm not really sure |
07:06 | <ljharb> | but `...{b}` is 100% redundant for `b` |
07:06 | <ljharb> | further destructuring the rest array in an array destructuring isn't always 1:1 |
07:07 | <bendtherules> | not 1:1 as in? |
07:08 | <bendtherules> | It will still take values out of the iterator in the same way, right? |
07:08 | <ljharb> | yeah, i suppose the nested array destructuring inside rest doesn't make much sense |
07:09 | <ljharb> | ie `[a, ...[b, ...c]] =` is the same as `[a, b, ...c]` |
07:09 | <bendtherules> | I can only think of one thing. correct me if i am wrong |
07:09 | <bendtherules> | the second one will still take out all values of all the iterator |
07:09 | <bendtherules> | *value out of the iterator |
07:09 | <ljharb> | so will the first one |
07:10 | <bendtherules> | i mean `[a, b]` vs `[a, ...[b]]` |
07:10 | <bendtherules> | Yes, in your example it will be the same thing |
07:14 | <bendtherules> | About `...{b}` being same as `b` - Is it exactly the same thing (if it was allowed)? |
07:15 | <bendtherules> | `...{b}` would still GET all the remaining enumerable properties, right? |
07:15 | <bendtherules> | Can that have a side effect? |
07:18 | <ljharb> | yes, i suppose that could |
07:21 | <bendtherules> | Was this willingly left out for some reason? |
07:21 | <bendtherules> | Looking through the early errors, i see that AssignmentRestProperty is restricted, but AssignmentRestElement is not |
07:26 | <bendtherules> | Also about the `[a, ...{length: b}]` case - what are the usecases? |
07:27 | <bendtherules> | Because the ... part is always a new array, it will have just numeric indexes and length property. What i can think of - get a random index value, or get length of remaining elements. |
07:27 | <ljharb> | i don't honestly know the history |
07:27 | <ljharb> | your thinking seems reasonable to me tho |
07:28 | <bendtherules> | got it. Last question - can i somehow track the discussions of this proposal (because it is already merged, i suppose)? |
07:29 | <ljharb> | destructuring was in ES2015, so it's long since shipped, and never went through the current proposal process. |
07:30 | <ljharb> | any discussions would be in the notes, not likely on github |
07:34 | <bendtherules> | 👍 Makes sense. Thanks for the help @ljharb. |
15:49 | <Bakkot> | ljharb / bendtherules: object rest/spread was not in ES2015 and was a "modern" proposal |
15:50 | <Bakkot> | its repo is at https://github.com/tc39/proposal-object-rest-spread |
16:15 | <ljharb> | right sorry, object destructuring was but not rest, that was later |
16:16 | <Bakkot> | I actually recall talking about this specific question at the time but I can't find it in the notes |
16:48 | <bendtherules> | I just found this - https://github.com/tc39/notes/blob/015f9392787bd9cb86f172af3d55d0475e87db26/meetings/2017-05/may-23.md |
16:49 | <bendtherules> | Which seems like when rest in obj dest. was decided to be not allowed |
16:49 | <Bakkot> | aha, yes, that's the conversation I was thinking of |
16:50 | <bendtherules> | @Bakkot: do you remember if there was similar discussion within array dest.? |
16:50 | <Bakkot> | bendtherules: that's before my time, alas |
16:50 | <Bakkot> | array rest/spread was in ES2015, so it was discussed earlier |
16:51 | <bendtherules> | Ok, I'll try to search later |
16:51 | <Bakkot> | https://github.com/tc39/notes/blob/8e8bfcbddcb29c09a10b0845a55af2e0d31b6f49/meetings/2015-07/july-28.md#66-bindingrestelement-should-allow-a-bindingpattern-ala-assignmentrestelement |
16:52 | <bendtherules> | And @ljharb - seems like there is a diff between `{a, ...{b} } ` and the basic form - because it only takes from own props |
17:24 | <bendtherules> | @Bakkot: hmm, so binding was made similar to assignment in array rest case. Wondering if the assignment case was decided on purpose or discussed earlier. |
17:37 | <bendtherules> | Ok, so some more discussions are here - https://github.com/tc39/proposal-object-rest-spread/issues/43#issuecomment-307957597 |
17:39 | <bendtherules> | In conclusion, it feels like there wasn't a strong case for obj destructuring within obj, but the array stuff was already there by that time. That wasn't removed as such. |
18:33 | <ljharb> | bendtherules: ah true |