| 00:44 | <ljharb> | I will be happy to revisit it and add the omitted data properties as a proposal once the websites are fixed. I can’t speak to chromes opinion on that tho. |
| 00:47 | <bakkot> | assuming it's web-compat to do so, which it may not be |
| 00:47 | <bakkot> | whereas it would almost certainly be web-compat to change the accessors to data properties as long as the people in this room agreed not to rely on them being accessors |
| 01:35 | <rbuckton> | Do we just need to spec a special data property flag that allows assignment of the property on an instance even if the prototype is non-writable/non-configurable? It seems to me this isn't the last time this will come up. |
| 02:13 | <bakkot> | I think that would be worse than just having a bunch of accessors. |
| 17:14 | <littledan> | FYI I will miss the first 90 minutes today |
| 17:22 | <Michael Ficarra> | Rezvan: Does Chrome have a position here? If these properties are omitted for now, would you consider attempting to add data properties again in the future, or are accessors the only option? |
| 18:02 | <Chris de Almeida> | #jsx:matrix.org |
| 18:04 | <rbuckton> | I wonder if a generalized canParse solution for JS would be viable as an alternative to using eval or Function for syntactic feature testing |
| 18:09 | <Richard Gibson> | I wonder if a generalized |
| 18:13 | <bakkot> | how do people feel about
as in
|
| 18:14 | <bakkot> | only works for functions not methods, I guess |
| 18:15 | <bakkot> | guess there could be a tryWithThis which would let you do JSON.parse.try(JSON, string) |
| 18:15 | <ljharb> | i like that (the non-method one), it has the side benefit that it encourages use of standalone functions |
| 18:17 | <Richard Gibson> | let { success, value } = tryApply(fn, thisArgument, argumentsList) would be language-consistent but less ergonomic |
| 18:17 | <bakkot> | fn.tryApply(thisArgument, argumentsList) is at least as consistent, surely |
| 18:18 | <ljharb> | i'd swap those two but sure (thisArg goes last, just like all the array methods, since it's more optional than args) |
| 18:18 | <Richard Gibson> | or I guess fn.tryCall(thisArgument, ...args) |
| 18:18 | <rbuckton> | i'd swap those two but sure (thisArg should come first, like call and apply |
| 18:19 | <ljharb> | oh hm, i guess i see that argument too |
| 18:19 | <bakkot> | but also I would want a version that doesn't take this at all |
| 18:19 | <snek> | i get this feeling that like |
| 18:19 | <bakkot> | so specifically I think I like best .try, which is only useful for non-methods, and .tryCall, which adds an initial this parameter |
| 18:19 | <ljharb> | yeah if the thisArg has to come first in a call/apply variant then i'd def want yet another one that omitted the receiver entirely |
| 18:19 | <snek> | async modules are some sort of fundamental failure |
| 18:19 | <Richard Gibson> | yeah, that's the friction point |
| 18:19 | <snek> | because everyone keeps trying to build ways to disable them |
| 18:19 | <snek> | but i don't want them to be some sort of fundamental failure |
| 18:19 | <snek> | i really like them |
| 18:20 | <bakkot> | agreed on both points |
| 18:23 | <snek> | another place where async modules were no longer used https://github.com/WebAssembly/esm-integration/pull/76 |
| 18:24 | <ljharb> | lol if we end up doing a directive, there's going to be a deluge of pragma/directive proposals once "no more modes" isn't a law anymore |
| 18:25 | <bakkot> | eh, I think directives which either evaluate normally or cause errors aren't really new modes |
| 18:25 | <nicolo-ribaudo> | This directive wouldn't be a new mode like strict vs sloppy |
| 18:25 | <nicolo-ribaudo> | It doesn't introduce a new "language version" |
| 18:25 | <nicolo-ribaudo> | No more than doing the same through any other syntax |
| 18:25 | <ljharb> | lol yeah i understand the nuance, but i don't think it will come across |
| 18:29 | <rbuckton> | export with { sync: true }? Not a huge fan of how it reads though. |
| 18:29 | <ljharb> | ps here's a relevant snippet from the notes from 2018 related to this exact problem: https://github.com/tc39/notes/blob/df1449925841bc77574e8e127611234670275575/meetings/2019-03/mar-28.md?plain=1#L507-L519 |
| 18:36 | <snek> | oh man i would hate if nodejs was another reason for people to not use async modules |
| 18:36 | <snek> | that would kill me |
| 18:40 | <peetk> | what about a function or bit of syntax that {tells you whether/asserts !} you've hit the event loop? i feel like that's always what you really care about in these worker listener cases |
| 18:48 | <nicolo-ribaudo> | If you have multiple script tags the event loop will start spinning before that the module even starts running, so it would always say "yes" |
| 18:50 | <nicolo-ribaudo> | Example: you load an analytics script and your main entry point module, and the analytics script already spins the event loop |
| 18:56 | <peetk> | then that would be the correct result right? |
| 18:56 | <peetk> | if you are a worker and you need to register listeners to handle messages then you absolutely must register them before you hit the event loop |
| 18:58 | <Rob Palmer> | I see a barrel library |
| 19:00 | <ljharb> | deferred imports make me very nervous; a keyword on export that's a lazily evaluated thing on the first import seems pretty nice - it might turn treeshaking from a half-assed hack into a reliable mechanism |
| 19:02 | <Rob Palmer> | It's like runtime treeshaking. You only get the bits of the barrel you need. |
| 19:03 | <bakkot> | ... treeshaking seems like a pretty reliable mechanism in the current world in fact? |
| 19:03 | <Rob Palmer> | And it can progressively load more of the barrel just-in-time |
| 19:03 | <ljharb> | ... treeshaking seems like a pretty reliable mechanism in the current world in fact? |
| 19:03 | <ljharb> | coinbase's react native app size dropped by 71% (seventy-one, not a typo) with that change |
| 19:04 | <Jack Works> | it should really make defer become default back when tc39 design ES module in ES6 |
| 19:04 | <Rob Palmer> | Tree-shaking only works when the compiler can see the full-scope of the program. That's not always possible in dynamically linked systems. |
| 19:05 | <Rob Palmer> | The perf issues of barrel files are well-documented https://marvinh.dev/blog/speeding-up-javascript-ecosystem-part-7/ |
| 19:05 | <ljharb> | even then, my statement holds. coinbase's RN app had no dynamic linking. |
| 19:05 | <Jack Works> | and requires "sideEffects: false" in your package.json which is not everyone remembers to add |
| 19:06 | <ljharb> | and which isn't granular enough to support packages with one side-effecting code path and many non-side-effecting code paths, eg |
| 19:07 | <snek> | i can confirm, importing fewer things is faster |
| 19:09 | <Jack Works> | and which isn't granular enough to support packages with one side-effecting code path and many non-side-effecting code paths, eg "sideEffects": ["./src/init/**"] |
| 19:10 | <ljharb> | ooh, TIL, thanks |
| 19:12 | <bakkot> | coinbase's react native app size dropped by 71% (seventy-one, not a typo) with that change |
| 19:13 | <ljharb> | no, it's that treeshaking simply isn't capable of safely judging that, and so the necessary heuristics leave behind way more code than is actually used |
| 19:13 | <ljharb> | in the past, rollup's heuristics (when rollup was the only treeshaker) were too aggressive, and it broke airbnb.com in IE for months, so it's a really hard line to walk |
| 19:13 | <bakkot> | that has not been my experience at all; do you have an example where the heuristics fail? |
| 19:14 | <ljharb> | tbf i haven't dived into treeshaking tools to know exactly what it is; that's just the sense i have seeing the empirical results |
| 19:15 | <Rob Palmer> | Statically judging whether JS code has side-effects is hard - probably impossible - so compilers take a safety-first approach and bail out unless they are really sure dead code is safe to remove. This is why treeshaking is not always effective. |
| 19:15 | <Michael Ficarra> | the lesson here should be just don't use side effects |
| 19:15 | <snek> | i wonder if this js code halts |
| 19:15 | <ljharb> | the lesson most of us have taken is, don't use barrel files :-) |
| 19:16 | <snek> | i wish prepack was still a thing |
| 19:18 | <Jack Works> | the lesson most of us have taken is, don't use barrel files :-) |
| 19:19 | <Ashley Claymore> | thankfully 0% of my code has side-effects, it's all overhead |
| 19:19 | <bakkot> | Statically judging whether JS code has side-effects is hard - probably impossible - so compilers take a safety-first approach and bail out unless they are really sure dead code is safe to remove. This is why treeshaking is not always effective. |
| 19:19 | <bakkot> | I am surprised to learn this is not everyone's experience |
| 19:20 | <ljharb> | tbh i'm surprised it's anyone's. the above article got quite a lot of +1s on twitter and virtually no pushback that i saw |
| 19:20 | <Michael Ficarra> | after reading the article on what these are, I feel like this should have been obvious from the beginning |
| 19:20 | <Michael Ficarra> | people be crazy |
| 19:21 | <bakkot> | the article above was only talking runtime, not treeshaking |
| 19:21 | <bakkot> | in fact it specifically says "treeshaking solves this" |
| 19:21 | <bakkot> |
|
| 19:21 | <Michael Ficarra> | "waah, I want one import line instead of five, I'm going to blindly merge others' namespaces, that seems like an okay trade-off" |
| 19:22 | <Michael Ficarra> | 🤮 |
| 19:24 | <ljharb> | ah fair, i was remembering some twitter discussion then i guess, not the article |
| 19:26 | <ljharb> | multiple exports was a mistake |
| 19:36 | <Michael Ficarra> | ugh we have a bug in PerformEval: it doesn't ever ToString its argument https://tc39.es/ecma262/#sec-performeval |
| 19:37 | <Michael Ficarra> | oh wait, never mind, it just can't reach that point without being a String |
| 19:37 | <Michael Ficarra> | I got it |
| 19:41 | <bakkot> | the thing where eval is the identity function on non-string arguments is... very strange |
| 19:45 | <littledan> | I prefer option 2 because it will extend to TT better |
| 19:48 | <Ashley Claymore> |
|
| 19:48 | <Michael Ficarra> | ljharb: we need to figure out what we're going to do with iterator helpers ASAP |
| 19:49 | <Michael Ficarra> | the accessors approach seems safest to me, even if it makes us feel a little bit gross |
| 19:49 | <ljharb> | i'd love to hear v8's position on the two options, but i still don't feel that accessors are safer |
| 19:49 | <Michael Ficarra> | I won't die on that hill though; either solution works for now |
| 19:50 | <ljharb> | if we go with "omit" i will be happy to immediately make a new proposal to reintroduce them, and will coordinate with the person from the issue to track upgrading those sites, fwiw |
| 19:50 | <Michael Ficarra> | that doesn't mean you'll have engine support to experiment with shipping them though |
| 19:50 | <ljharb> | right, which is why i want to hear v8's position first |
| 19:50 | <Michael Ficarra> | Rezvan is the V8 rep at this meeting |
| 19:51 | <Michael Ficarra> | unsafeMaybeNotAString("v") |
| 19:53 | <Ashley Claymore> |
|
| 19:53 | <Ashley Claymore> | Level 2 |
| 19:54 | <rbuckton> | I'm generally partial to "omit" as well. While I understand bakkot's concerns around x.constructor === whatever, I think there is a fairly low likelihood of that becoming a problem if there is a short turnaround on a follow-on proposal and the outstanding sites being fixed. |
| 19:54 | <Ashley Claymore> | can strings be quines |
| 19:56 | <Ashley Claymore> |
|
| 19:56 | <Michael Ficarra> | also the toString of an Iterator will change |
| 19:56 | <rbuckton> | Though I still think there's potential for a general solution to the "override mistake", such as adding a new PropertyDescriptor flag to opt-in to a behavior that allows setting on an instance even if the property is frozen on the prototype. |
| 19:56 | <rbuckton> | From what it is in the proposal spec, or do you mean from what it is on %IteratorPrototype% currently? |
| 19:57 | <Michael Ficarra> | from what's in the draft spec as of now |
| 19:57 | <Michael Ficarra> | it is proposed as "[object Iterator]" and will be "[object Object]" temporarily |
| 19:58 | <Michael Ficarra> | like... why do that? |
| 19:58 | <Michael Ficarra> | this is just unnecessary risk and I really don't see the upside other than warm fuzzies |
| 20:01 | <rbuckton> | I don't have a preference regarding toString/toStringTag, tbh. I generally wouldn't recommend relying on it for anything other than a debugging aid, so its presence or absence isn't that concerning to me. |
| 20:32 | <Rezvan> | right, which is why i want to hear v8's position first |
| 20:32 | <ljharb> | V8 is supporting the PR (https://github.com/tc39/proposal-iterator-helpers/pull/287) Michael talked about yesterday. This incompatibility blocked us for shipping iterator helpers. The solution provided in the PR seems to be the best way to resolve the issue. |
| 20:33 | <ljharb> | and additionally, with either approach, is Chrome willing to try to ship them as normal data properties in the future once the incompatible websites have finished upgrading? |
| 20:51 | <Rezvan> | thanks; and does v8 have an opinion about, instead of the PR, just not implementing the constructor and Symbol.toStringTag properties for the time being? |
| 20:52 | <Rezvan> | and additionally, with either approach, is Chrome willing to try to ship them as normal data properties in the future once the incompatible websites have finished upgrading? |
| 20:59 | <hax (HE Shi-Jun)> | slide link of next topic: https://johnhax.net/2023/slice/slide |
| 21:00 | <Michael Ficarra> | Rezvan ljharb we didn't talk about that |
| 21:02 | <Rezvan> | So, my answer was my opinion. Not sure if Shu thinks the same. |
| 21:13 | <Michael Ficarra> | I've never met anyone who knows the parameter meaning and order for both slice and splice off the top of their head |
| 21:13 | <Michael Ficarra> | other than slice(n), I look them up every time |
| 21:13 | <Chris de Almeida> | mdn. every time |
| 21:14 | <rbuckton> | mdn. every time |
| 21:14 | <Chris de Almeida> | my vscode-fu need polishing for sure |
| 21:14 | <ljharb> | i know slice but only because i've trained myself to see the "p" so hard, at which point i immediately have to look it up every time |
| 21:15 | <rbuckton> | my vscode-fu need polishing for sure array.slice( is enough assuming the language service knows array is an array type |
| 21:15 | <eemeli> | I can never remember which of the string methods support negative indices. |
| 21:16 | <Chris de Almeida> | Usually just |
| 21:16 | <Michael Ficarra> | this vscode example doesn't look like a bug to me |
| 21:16 | <rbuckton> | Yeah, not a bug. |
| 21:17 | <rbuckton> | The line assumes subcommand exists as an element, because that's the only way you can get to that line to begin with. |
| 21:18 | <Michael Ficarra> | that's what I figured |
| 21:29 | <Michael Ficarra> | :-( my queue reply was skipped |
| 21:29 | <Chris de Almeida> | apologies Michael Ficarra didn't see your reply in time |
| 21:30 | <Michael Ficarra> | this is why we need https://github.com/bterlson/tcq/issues/65 |
| 21:31 | <ljharb> | by "reified" do we mean like, a noun that represents a kind of "view" on an array/string? |
| 21:31 | <Michael Ficarra> | anyway, I was trying to point Ron to the https://github.com/tc39/proposal-iterator.range proposal where we have discussed having a reified range |
| 21:32 | <Michael Ficarra> | I personally support it, but most others seemed to reject it |
| 21:32 | <Michael Ficarra> | ljharb: basically a data structure that holds bounds and can be passed between the [] to do the slice |
| 21:33 | <ljharb> | yeah that sounds super unjavascripty to me |
| 21:34 | <rbuckton> | My suggestion for reification is the introduction of "inverted" get/set/has/delete via symbols that could be looked up on an Object in lieu of ToPrimitive:
Which has a general utility for custom indexes, such as turning a
|
| 21:34 | <ljharb> | making an actual thing vs just typing x => x[a, b](y) doesn't seem worth adding |
| 21:36 | <bakkot> | I would definitely not want that to work with normal obj[key] access, but could see using the obj[^key] syntax or something |
| 21:36 | <rbuckton> | That can't be unwrapped though |
| 21:36 | <ljharb> | and while i see ron's point that making a special kind of value and a special protocol to go with it would be a logical generalization, that's a ton of complexity that it'd be a hard sell to justify |
| 21:36 | <bakkot> | though I don't see why you want to do it in this inverted way - it seems like usually containers know how to use an index, rather than an index knowing how to use a container? |
| 21:36 | <rbuckton> | i.e., x => x[a, b] doesn't let you extract a and b as there's no associated data model. |
| 21:37 | <ljharb> | so would we also have a PropertyKey that represents a property, takes an object, and does an inverted lookup? |
| 21:37 | <ljharb> | oh lol yeah sorry x.slice(a, b) in this case, i mistyped. but yes it doesn't let you get at the a and b, which seems like a benefit? (to make it an opaque lens) |
| 21:38 | <bakkot> | I think my preference here would be to leave obj[x] alone, and to add a new obj[^x] which invokes a symbol-named method on obj passing it x (uncoerced). there could then be a slice(a, b) function which returns a reified Slice, and the symbol-named method on Array could know how to deal with that |
| 21:39 | <bakkot> | also you could have the symbol-named method on Map be an alias for get, and that sort of thing |
| 21:39 | <rbuckton> | though I don't see why you want to do it in this inverted way - it seems like usually containers know how to use an index, rather than an index knowing how to use a container? [] is only useful for strings and symbols (i.e., via toPrimitive). You can't put anything else meaningful in there that isn't either. |
| 21:39 | <bakkot> | and of course have a similarly named method to be invoked when doing obj[^x] = y |
| 21:39 | <Michael Ficarra> | yeah I would also not want a[b] delegating to a protocol |
| 21:40 | <rbuckton> | I'm surprised the WeakMap example isn't a stronger motivator? |
| 21:40 | <ljharb> | weak things are used so rarely i don't think it'd motivate any ergonomic changes? |
| 21:42 | <bakkot> | the WeakMap example seems actively bad to me? if I see obj[key] = 1 I am really expecting to set a property on obj. if it does something other than that this is bad. |
| 21:43 | <eemeli> | Could someone clarify if we're talking about just the slice 1:2 proposal now, or also the ^ one? |
| 21:43 | <ljharb> | whereas map[^key] = value seems nice (altho i'm not sure how it'd work with set) |
| 21:44 | <rbuckton> | the WeakMap example seems actively bad to me? if I see |
| 21:44 | <bakkot> | ljharb: I am imagining that map[^key] = value is sugar for map[Symbol.set](key, value) |
| 21:44 | <ljharb> | i would agree |
| 21:44 | <waldemar> | Could someone clarify if we're talking about just the slice |
| 21:45 | <rbuckton> | ljharb: I am imagining that [^x] to mean index-from-end. |
| 21:45 | <ljharb> | right, we've been talking about a new imagined proposal for [^x] to not necessarily mean from end |
| 21:45 | <ljharb> | however arr[^-1] could map to .slice or .at, solving that problem |
| 21:45 | <bakkot> | rbuckton: not if Array.prototype[Symbol.set] = function(key, value) { key < 0 ? this[this.length + key] = value : this[key] = value }! |
| 21:45 | <rbuckton> | the WeakMap example seems actively bad to me? if I see Symbol.toPrimitive |
| 21:46 | <rbuckton> | And an explicit Symbol.geti seems directly in line with "stop coercing things". |
| 21:47 | <bakkot> | "stop coercing things" is mainly intended to apply to new APIs, not to change the meaning of existing things |
| 21:47 | <bakkot> | I don't want to change the meaning of existing things as a rule |
| 21:49 | <bakkot> | but also, even in a world where I thought changing the meaning of obj[key] was a good idea, I would still think that it would invoke a method on obj, not a method on key |
| 21:49 | <rbuckton> | Honestly, I'd love to be able to hook a[x] directly to better support custom collections. Indexing with things other than string/number is fairly common in many languages, and is extremely limiting in JS. Symbol.geti avoids hooking all of a[x] for a specific class of key-like things. |
| 21:50 | <bakkot> | My suggestion is to add a new syntax for such cases. |
| 21:50 | <Michael Ficarra> | rbuckton: a[b] needs to have simple semantics |
| 21:50 | <rbuckton> | rbuckton: |
| 21:50 | <bakkot> | I don't think we should change a[x], but I think we could reasonably introduce a[^x], which would allow a to define how it should be indexed by arbitrary x |
| 21:50 | <rbuckton> | My suggestion is to add a new syntax for such cases. |
| 21:51 | <Michael Ficarra> | sorry, a better thing to say would be "there needs to be property access with simple semantics; a[b] serves that purpose already" |
| 21:51 | <ljharb> | put more strongly, changing a[x] would likely break a lot of assumptions in existing code and in the minds of existing devs, and i doubt there would ever be consensus for that, such that i think it's a waste of time to pursue it. |
| 21:51 | <Michael Ficarra> | yeah, changing that is almost certainly dead in the water |
| 21:52 | <rbuckton> | I don't think we should change a[^x] specifically as I'd really like it to not mean different things in different places (negative index on Arrays, something else somewhere else, etc) |
| 21:52 | <ljharb> | if that were possible then i would assume we'd have added objects as object keys and not symbols |
| 21:52 | <ljharb> | If we introduced a new syntax for indexing, I'd be opposed to |
| 21:52 | <rbuckton> | Especially given the prior art for the ^x syntax in C#. |
| 21:52 | <littledan> | I was hoping that we could save prefix ^ for something more interesting, e.g., shorthand for zero-parameter arrow functions |
| 21:52 | <bakkot> | If we introduced a new syntax for indexing, I'd be opposed to [^x] was just an idea. [@x] or something also fine. |
| 21:53 | <Michael Ficarra> | hax (HE Shi-Jun): I will definitely help, but I don't think I can sign up for co-championing |
| 21:53 | <ljharb> | or obj@[x], we could be creative |
| 21:53 | <Michael Ficarra> | there's only so much time I have to dedicate to TC39 stuff and I need to prioritise things |
| 21:53 | <ljharb> | (like protocols) |
| 21:54 | <rbuckton> | For partial application I'd considered an infix ~ as an indicator, i.e. a~(). I could see a~[x] as an option for custom syntax, but I still don't think custom syntax is merited if we could easily hook a[x] for a very specific set of things. |
| 21:54 | <Michael Ficarra> | lol tell me about it |
| 21:54 | <ljharb> | it's very very important that that syntax not be more hookable than it already is, getters are bad enough |
| 21:54 | <Michael Ficarra> | if iterator helpers and follow-ons weren't so damn useful and popular... |
| 21:54 | <hax (HE Shi-Jun)> | there's only so much time I have to dedicate to TC39 stuff and I need to prioritise things |
| 21:54 | <rbuckton> | You could imagine Symbol as being implemented this way, and the addition of Symbol to x[a] was a change to an existing thing back in 2015 |
| 21:54 | <Michael Ficarra> | or if someone else was working on them |
| 21:55 | <ljharb> | in the next half year i may have time to help with some of those, fwiw |
| 21:55 | <hax (HE Shi-Jun)> | I'm ok with other syntax, but to be honest I don't see how diff with a[^i]. |
| 21:55 | <Michael Ficarra> | Thank you ! I just try to advance it it the simple form which I believe is the best solution on these problems. |
| 21:56 | <hax (HE Shi-Jun)> | So it seems I have nothing could do... |
| 21:56 | <ethanarrowood> | No more ('b' + 'a' + + 'a' + 'a').toLowerCase()? |
| 21:56 | <rbuckton> | As a counterpoint to a[@x] or whatever. if x is a reified slice, I would want a way to explicitly throw when it is used via a[x], since that would be a mistake. |
| 21:57 | <ljharb> | reified properties/indexes/object operations don't sound like a great direction to me personally, we have functions for that. |
| 21:57 | <rbuckton> | If the things we want to use with a[@x] shouldn't be used with a[x], then we have two mutually exclusive syntaxes that arguably do the same thing depending on their inputs. |
| 21:57 | <rbuckton> | And that doesn't seem like a valuable use of our syntactic budget if we could merge them into just a[x]. |
| 21:58 | <ljharb> | imo robustness of existing syntax > > > preserving syntax budget |
| 21:58 | <Michael Ficarra> | rbuckton: a[b] delegating to a symbol is just not going to happen |
| 21:58 | <rbuckton> | a[x] isn't robust, its wasteful |
| 21:58 | <ljharb> | lol what's wasteful about it as-is? |
| 21:58 | <ljharb> | (other than that getters exist) |
| 21:58 | <Michael Ficarra> | engines will not let that highly-optimised, extremely common operation become slow |
| 21:59 | <rbuckton> | That you can't use non-string, non-symbol values as keys withing them being stringified. |
| 21:59 | <rbuckton> | engines will not let that highly-optimised, extremely common operation become slow a[{}] today, since they already have to patch in a call to Symbol.toPrimitive. |
| 21:59 | <Michael Ficarra> | they may all be done by then 💪 |
| 22:00 | <rbuckton> | So I don't imagine it would affect performance at all in the common case. |
| 22:00 | <Michael Ficarra> | only if anyone anywhere has ever touched Symbol.toPrimitive, which they usually haven't |
| 22:01 | <rbuckton> | only if anyone anywhere has ever touched .toString() for the same thing |
| 22:01 | <rbuckton> | I'm using Symbol.toPrimitive as a general placeholder for all the things ToPropertyKey does for Object values |
| 22:01 | <Michael Ficarra> | 🤷♂️ well it'll be up to you to convince engines of that then |
| 22:11 | <rbuckton> | To be clear, I haven't proposed In lieu of |
| 22:15 | <Michael Ficarra> | rbuckton: I encourage you to participate in the Iterator.range issue tracker |
| 22:18 | <rbuckton> | rbuckton: I encourage you to participate in the Iterator.range issue tracker Iterator.range? Do you have a particular issue this applies to? Ranges and slices are subtly different. I think I did bring up reified slices when Iterator.range was proposed, but I haven't had much time to follow the range proposal since then. |
| 22:18 | <ljharb> | reified ranges seem just as unjavascripty to me as reified slices |
| 22:19 | <Michael Ficarra> | rbuckton: I don't see how they are different |
| 22:19 | <rbuckton> | It's very pythony, and python and JS share many similarities. |
| 22:19 | <Richard Gibson> | string enums are nice until a change results in garbage like step 24 in https://tc39.es/ecma402/#sec-initializenumberformat |
| 22:21 | <rbuckton> | rbuckton: I don't see how they are different |
| 22:21 | <rbuckton> | Hence why I said they are subtly different |
| 22:21 | <Michael Ficarra> | I hadn't considered that a reified slice would try to represent relative indexing |
| 22:22 | <rbuckton> | That was in the slides. |
| 22:22 | <rbuckton> | x:^y |
| 22:22 | <Michael Ficarra> | lol sure, there was a lot of things in the slides |
| 22:23 | <rbuckton> | The slice syntax is essentially expr:expr, so 0:1 or x:y. If you want to represent .slice(0, -1), you use x:^y |
| 22:24 | <rbuckton> | Mostly to avoid the disparity with
|
| 22:25 | <rbuckton> | Thus, a Slice(x, y) is actually a pair of Index objects. x:^y would be reified as new Slice(new Index(x, false), new Index(y, true)). At least, that's how it works in C#. |
| 22:26 | <hax (HE Shi-Jun)> | Refication of index/range are good I believe, the problem is we never have such things in js, all js current methods are just calculate eaglely, for example, this is how resizeable typedarray deal with negative index. |
| 22:27 | <rbuckton> | That also ensures the types are consistent and the object model is more user friendly if you want to do something like:
|
| 22:27 | <hax (HE Shi-Jun)> | Another problem, if there will be index/range I will really hope they are new primitive types. But it seems very impossible as current status. |
| 22:28 | <rbuckton> | Refication of index/range are good I believe, the problem is we never have such things in js, all js current methods are just calculate eaglely, for example, this is how resizeable typedarray deal with negative index. x:y, and a reified range like x..y as two distinct things. |
| 22:28 | <rbuckton> | Another problem, if there will be index/range I will really hope they are new primitive types. But it seems very impossible as current status. |
| 22:29 | <rbuckton> | Though == and !== might be nice, most other operators don't apply to slices and indexes. |
| 22:29 | <rbuckton> | You can't really compare ^0 and ^1 using < or > as they may point to the same element if the array only has a single element. |
| 22:30 | <hax (HE Shi-Jun)> | Primitives aren't really necessary for this. Regular expression literals produce Objects |
| 22:31 | <rbuckton> | Also, range might accept floats, while a slice should only accept integral number values, bigint, and Index, and not coerce |
| 22:32 | <rbuckton> | Also, a slice of x:y could theoretically hold a non-primitive, so it can't be a primitive. |
| 22:32 | <Michael Ficarra> | does this not fall under the "don't coerce objects to primitives"? |
| 22:33 | <rbuckton> | does this not fall under the "don't coerce objects to primitives"? |
| 22:34 | <Michael Ficarra> | no, I'm talking about the coercion slides |
| 22:34 | <Michael Ficarra> | null -> some primitive |
| 22:36 | <Michael Ficarra> | these tables are soooooo helpful |
| 22:53 | <rbuckton> | "you haveundefined notifications to review" |
| 22:53 | <rbuckton> | (or NaN) |
| 22:55 | <rbuckton> | IMO, the value for Numbers and BigInts taking strings makes sense given the DOM return value rationale |
| 22:58 | <Michael Ficarra> | yeah numeric strings are all over the place in the DOM, and JS kinda has to work nicely with the DOM or people will get mad |
| 22:59 | <eemeli> | "you haveundefined notifications to review" Hopefully in an Intl.MessageFormat world, that message would read:
|
| 23:00 | <rbuckton> |
|
| 23:09 | <bakkot> | As a counterpoint to |
| 23:09 | <bakkot> | that seems fairly straightforward to me, not really a counterpoint |
| 23:09 | <bakkot> | but, I also don't see why it would be a mistake? |
| 23:09 | <bakkot> | like if the class knows how to handle slices, like Array, then it would just give you the slice |
| 23:10 | <bakkot> | from its Symbol.get method |
| 23:11 | <rbuckton> | but, I also don't see why it would be a mistake? Slice needs to be used with a[@x], then using it with a[x] is 100% a bug. |
| 23:13 | <bakkot> | oh, sorry, I misread |
| 23:13 | <bakkot> | yes, using with a[x] is a bug, and would be covered by having slice's Symbol.toPrimitive throw |
| 23:13 | <rbuckton> | just make the Symbol.toPrimitive method on the Slice class throw? a[x] and what you would use in a[@x] would be mutually exclusive to avoid bugs. If they are mutually exclusive, then just having a[x] do both would avoid the concern about trying to pick the right one to avoid a bug. |
| 23:13 | <bakkot> | ah, well, they would not be totally mutually exclusive |
| 23:13 | <bakkot> | because Array could have a[@-1] do negative indexing |
| 23:14 | <rbuckton> | ah, well, they would not be totally mutually exclusive |
| 23:14 | <bakkot> | they would be mutually exclusive for object types though, yes |
| 23:14 | <bakkot> | why? if I do map[@"string"], that can do a map lookup |
| 23:14 | <rbuckton> | because Array could have a[-1] would not, thus its still a potential bug |
| 23:14 | <bakkot> | Well, yes, a[-1] would be a bug but in general passing things to the wrong place is a bug |
| 23:15 | <rbuckton> | why? if I do map["string"] and it mean something different. |
| 23:15 | <bakkot> | If that's true it applies to any special syntax for indexing a map. I don't agree. |
| 23:16 | <rbuckton> | I'm not advocating for indexing a map using []. |
| 23:16 | <bakkot> | Right, but I am |
| 23:16 | <bakkot> | and above you were advocating for a way to index collection types by non-string values; Map seems like the obvious collection type you'd most want to index by non-string values |
| 23:17 | <rbuckton> | I'm advocating for doing something meaningful with objects in a[x] aside from just ToString(). |
| 23:18 | <bakkot> | What problems does that solve? |
| 23:20 | <bakkot> | My suggestion is, introduce a new
so it gives you a lot of stuff! |
| 23:20 | <rbuckton> | It solves reified
|
| 23:21 | <bakkot> | Your suggestion only solves reified Index if either there is also an "indexing" protocol collection types can opt into, or the Index type knows about every single kind of collection |
| 23:21 | <rbuckton> | I was also considering geti as an approach to handling concurrent reads/writes in multithreaded javascript with Worker and shared structs, though I'm also looking into .{ notation as a solution |
| 23:21 | <bakkot> | Ditto pick, etc |
| 23:21 | <rbuckton> | Yes, I expected there would also be an indexing protocol, just like slice notation added a slice protocol. |
| 23:21 | <bakkot> | and slice |
| 23:22 | <rbuckton> | Pick, not so much. |
| 23:22 | <rbuckton> | Slice depends on knowing something about the size of a collection. Pick does not. |
| 23:22 | <bakkot> | OK, so, my proposal does not require having an indexing protocol, or a slice protocol. If there is a slice type, and a pick type, then collections can define for themselves what to do when asked to "slice" or "pick" something, without needing a protocol. That seems better. |
| 23:23 | <rbuckton> | I don't agree that it's better. |
| 23:23 | <rbuckton> | Slice and index-from-end have a well-defined protocol that multiple different objects could implement. |
| 23:24 | <bakkot> | The way I am suggesting they implement that is, they define a Symbol.get method which has specific behavior for the reified slice values. |
| 23:24 | <rbuckton> | If I have a Slice and use it on an array via a[@x], I get a slice. If I used it on a Map via a[@x], it might just act as a key, thus it's not interpreted as a slice. That means that a[@x:y] would do something strange on a Map. |
| 23:25 | <bakkot> | Yes, if you use a key with a type of collection which does not know how to interpret that key, you're going to have a bad time. But this is also true in your inverted world if you use a key with a type of collection where the key does not know how to interpret that type of collection. |
| 23:26 | <rbuckton> | Ignoring the @ for a second, a[x:y] and a[^x] should always be interpreted as "take a slice from a" and "get the element from a relative from its end". |
| 23:27 | <rbuckton> | Yes, if you use a key with a type of collection which does not know how to interpret that key, you're going to have a bad time. But this is also true in your inverted world if you use a key with a type of collection where the key does not know how to interpret that type of collection. |
| 23:28 | <bakkot> | Ignoring the a[x:y] or negative-indexing a[^x]. I think that having only a general a[@x] hook would solve the use cases for both a[x:y] and a[^x]. |
| 23:28 | <rbuckton> | With
|
| 23:30 | <rbuckton> | The same goes for
|
| 23:31 | <rbuckton> | (or something to that effect) |
| 23:31 | <bakkot> | With my proposal also: Array.prototype[Symbol.get] = function(v) { if (Slice.isSlice(v)) return this.slice(v.start, v.end); /*...*/ } |
| 23:31 | <bakkot> | And it only requires a single protocol, not two. |
| 23:33 | <rbuckton> | But a
and a
|
| 23:34 | <bakkot> | (I really do not think it makes sense for keys to define how they interact with collections, rather than collections defining how they interact with keys.) |
| 23:34 | <rbuckton> | With my proposal also: a[@x:y] potentially not returning a Slice and maybe doing something else instead of erroring in the case of a Map. |
| 23:35 | <bakkot> | I am specifically not proposing to have a[@x:y] syntax |
| 23:35 | <rbuckton> | (I really do not think it makes sense for keys to define how they interact with collections, rather than collections defining how they interact with keys.) |
| 23:36 | <bakkot> | But yes, if you have a reified slice type, and you try to index a map by that, the appropriate behavior is to look up the slice instance in the map. That's how maps work. |
| 23:37 | <rbuckton> | And as I said, I'd be happy to have Slice and Index have special handling in indexers even without the symbols. That's what C# does. I just feel that geti adds a bit more flexibility. |
| 23:37 | <rbuckton> | But I don't think leveraging a general indexing hook to handle Slice and Index is a good idea. |
| 23:38 | <rbuckton> | But yes, if you have a reified slice type, and you try to index a map by that, the appropriate behavior is to look up the slice instance in the map. That's how maps work. a[x:y] (or a[@x:y]) on a Map that doesn't undertand how to handle a slice should be to throw. Not silently do the wrong thing. |
| 23:42 | <rbuckton> | Or if you expect a[@x:y] to just be a generalized map indexer, then I'd still strongly prefer we have specific handling for a[x:y] and a[^x], such that slicing with the correct syntax is always slicing, and that a[@x] just doesn't care at all what you put into it. Documentation that describes slicing with syntax should always refer to a[x:y], and it should never be recommended that you abuse something like Symbol.get/a[@x] to handle slicing. It's just a bug farm and a source of confusion. |
| 23:47 | <rbuckton> | C# lets you write map[0..1] as a key, but C# is typed and thus you know that the input/output is when indexing using the key type. JS isn't typed, so its far easier to do the wrong thing. |
| 23:56 | <rbuckton> | As an aside, I'm not sure what symbol you would want to use for a[@b]? You can't use @ because of decorators, and I'd prefer to keep ^x for reified relative index if possible, so it either has to be an infix operator, or a prefix operator that comes before the [. I'd like to avoid using & and * due to both their precedence for use with pointers in other C-like languages, and that I'd really like to use & for the ref proposal if a ref keyword ends up not being feasible (since ref has a close enough similarity to pointers that the semantic meaning seems reasonable). |
| 23:58 | <rbuckton> | % may be out as well. We'd considered it for pipeline, but IIRC % is hard to type on a number of international keyboard layouts. |