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. |