13:46 | <robpalme> | Jitsi video conferencing is now open. Meeting starts in 13 mins. |
14:14 | <wsdferdksl> | Is there a way to get rid of the #&$(*!@#(* buttons that the video conference software displays on top of the slides? |
14:16 | <rricard> | removing the mouse cursor from the window should do the trick |
14:17 | <wsdferdksl> | rricard: It doesn't. They're always there. Makes slides unreadable. |
14:18 | <rricard> | I would try clicking in the window and removing then |
14:19 | <wsdferdksl> | rricard: Tried that. Clicking in the window doesn't do anything. |
14:19 | <rricard> | well I don't know, I do use the electron client maybe it has the feature |
14:28 | <akirose> | wsdferdksl make your window taller |
14:41 | <michaelficarra> | wsdferdksl: paste this in your console: |
14:41 | <michaelficarra> | ((a) => a.parentNode.removeChild(a))(document.getElementsByClassName('toolbox-content')[0]) |
14:55 | <michaelficarra> | isn't Intl effectively all optional? why do we care that much about data size? |
14:57 | <Bakkot> | I don't think it's optional for browsers? |
14:57 | <ystartsev> | its not optional for browsers |
14:58 | <shu> | michaelficarra: who's "we"? the committee? |
14:58 | <michaelficarra> | shu: yes |
14:59 | <devsnek> | i wanted to add `\U{character name instead of codepoint}` but browsers were against it due to size |
14:59 | <michaelficarra> | ystartsev: Bakkot: The APIs are not optional, but the data set can be effectively empty, right? There should be no conformance issue. |
14:59 | <Bakkot> | what would be the point of that |
14:59 | <shu> | yeah conformance is not a goal for products |
14:59 | <devsnek> | that's what node did for years |
15:00 | <devsnek> | intl but all the intl apis return garbage |
15:00 | <shu> | well, that's a little overgeneralization. but conformance is never prioritized over actually providing useful APIs |
15:00 | <devsnek> | lol https://gc.gy/86635848.png |
15:00 | <michaelficarra> | because then we are saying, as a standards body, "if you want to provide this functionality, here is how you provide it. If it is too costly, you don't have to provide anything." |
15:01 | <shu> | michaelficarra: it in no way follows from that size doesn't matter |
15:01 | <shu> | you still want to make an effort to minimize cost so providing it is more likely |
15:02 | <Bakkot> | also we should not standardize things which no one is going to ship |
15:02 | <Bakkot> | or, worse, that they're going to ship in a form which is useless |
15:05 | <michaelficarra> | on the emoji names example, development time tooling could "support" the API and output a replacement |
15:05 | <michaelficarra> | I dunno, seems not entirely useless to standardise these things |
15:05 | <Bakkot> | standardizing a thing which has runtime implications but is only used at build time would be... strange |
15:06 | <devsnek> | there have been suggestions of having a build-time specification for js |
15:06 | <devsnek> | not sure how i feel about that but |
15:06 | <devsnek> | it would enable this sort of thing in one way |
15:08 | <Bakkot> | I generally feel like there should be implementations before a standard |
15:08 | <Bakkot> | like if webpack or whatever wants to add build-time stuff and other people want to interop with that, then it would be the appropriate time to standardize |
15:09 | <Bakkot> | but the implementations are the important part, we can't just summon them from the void by saying "wouldn't it be neat if something existed with these semantics" like happens with browsers |
15:09 | <devsnek> | yeah i think my perspective on that is that its so local that there would never be a need to standardize. you can always add `devsneks-cool-unicode-names-transform` to your package.json |
15:10 | <ystartsev> | michaelficarra: sorry my attention was split |
15:10 | <Bakkot> | sorry is this speaker "MD"? for the notes |
15:11 | <shu> | current speaker is Markus Scherer |
15:12 | <michaelficarra> | Bakkot: MWS |
15:12 | <Bakkot> | thanks |
15:12 | <michaelficarra> | other speakers in this topic are MB and MED |
15:14 | <Bakkot> | MED hasn't talked yet, right? |
15:15 | <michaelficarra> | yeah pretty sure he hasn't talked yet |
15:17 | <leobalter> | devsnek: https://gist.github.com/leobalter/16364bb167633cb3cb31e0f95e160a2a |
15:18 | <leobalter> | I had the chance to quickly discuss the topic with Rick. He did not review this gist but I believe I captured my thoughts there. |
15:19 | <devsnek> | leobalter: thanks for the writeup |
15:20 | <leobalter> | saying that, I'm sorry the discussion got heated from my side and I got off the rails yesterday. I'd appreciate to be part of the discussion, but that's not an excuse for being aggressive. |
15:24 | <devsnek> | no hard feelings... i'm grateful for your input |
15:30 | <leobalter> | devsnek: PTAL again, I included a note about coverage + engine262 |
15:30 | <devsnek> | 👍🏻 |
15:30 | <michaelficarra> | this is along the lines of the "nothing can casefold to ASCII" guarantee |
15:31 | <michaelficarra> | we just have to trust the Unicode consortium to not do stupid things |
15:32 | <Bakkot> | well, we don't just have to trust, we can ask them to write down that they won't |
15:32 | <Bakkot> | and then trust |
15:34 | <msaboff> | Instead of having to trust, why no use syntax to denote the type of a property and with what contructs if can be used? |
15:34 | <michaelficarra> | msaboff: eh, they both work in practice though |
15:35 | <michaelficarra> | sounds like Thomas hasn't written a parser |
15:35 | <Bakkot> | who is thomas |
15:35 | <Bakkot> | for the notes |
15:35 | <michaelficarra> | we already need Unicode data for ID_Start, ID_Continue, WSP, etc |
15:36 | <michaelficarra> | Bakkot: TLY |
15:36 | <Bakkot> | thanks |
15:36 | <michaelficarra> | I don't know who they represent |
15:36 | <shu> | Evernote apparently |
15:36 | <msaboff> | We require Unicode data for all the Unicode related properties. |
15:36 | <wsdferdksl> | gibson042: Nested [ [ ] ] ] are allowed in the existing lexical grammar. Follow the productions in 12.8.5 |
15:37 | <devsnek> | may we pray that 12.8.5 never changes ever |
15:52 | <gibson042> | RegularExpressionFirstChar and RegularExpressionChar don't allow unescaped `[` except as part of RegularExpressionClass `[…]`, which itself cannot contain unescaped `]` |
15:54 | <gibson042> | so I guess the tokenization doesn't follow the semantic structure, but nonetheless can work |
15:55 | <gibson042> | subject to the no-unescaped-`/` constraint |
16:03 | <wsdferdksl> | gibson042: This is exactly the reason why I had added the no-unescaped-/ constraint to the proposal here. |
16:57 | <robpalme> | we are starting up in 2 mins |
17:03 | <Bakkot> | can someone take over notes for the next 30 seconds, I want to start a cup of tea |
17:03 | <Bakkot> | won't be hard, bot likes shu |
17:05 | <Bakkot> | also someone fill in the last thirty seconds please, my network dropped |
17:20 | <Bakkot> | who is legendecas, for the notes? |
17:21 | <Bakkot> | I am having difficulty capturing this comments for the notes |
17:22 | <robpalme> | CZW |
17:23 | <rkirsling> | the example in the survey was absolutely lower case |
17:24 | <rkirsling> | because I wrote in the exact same concern, even though I don't think the quoted words were mine |
17:25 | <devsnek> | i don't think i saw the survey |
17:37 | <Bakkot> | a script could also call `Object.defineProperty(globalThis, 'GrowableSharedArrayBuffer', { value: globalThis.GrowableSharedArrayBuffer, writeable: false, configurable: false })` at the beginning of the script |
17:37 | <Bakkot> | so I am hopeful moddable can resolve this that way |
17:38 | <Bakkot> | (not saying that it needs to happen in the next thirty seconds) |
17:38 | <michaelficarra> | I just don't think it would be especially burdensome for Moddable to resolve this |
17:38 | <Bakkot> | likely not but it seems reasonable to say that they should get an opportunity to explore that |
17:40 | <michaelficarra> | sure, or at least to quantify that burden so we can better evaluate it as a committee |
17:42 | <Bakkot> | right |
17:42 | <msaboff> | I think Moddable's concern is not just this feature, but the precedent. |
17:43 | <Bakkot> | right, but if it turns out the precedent isn't actually a problem, that is ideal |
17:54 | <ystartsev> | For the record -- I didn't say this, but I support the proposal and appreciate all the work you did here to address mozilla's concerns shu |
17:54 | <Bakkot> | I would really prefer not to wake up at 6:30am if it's avoidable |
17:54 | <shu> | where was the concern with AggregateError? |
17:55 | <ystartsev> | I hope we have more time for that |
17:56 | <michaelficarra> | ugh I wish we were calling these immutable arrays and not tuples |
17:59 | <bradleymeck> | i have to go for a bit, just want to be sure I get to say I like this proposal but have concerns about conversation about the names using past forms of verbs (e.g. "I pushed 1 onto the array" .push()? or .pushed()?) |
18:00 | <ljharb> | shu: overlooked, really. i'd have brought it up then if it had occurred to me |
18:01 | <shu> | ljharb: and Realms/Compartments/whatever? |
18:01 | <ljharb> | shu: if there's a natural place to nest those, i think we should |
18:04 | <shu> | ljharb: and to clarify, your position here is purely organizational, right? |
18:05 | <ljharb> | shu: yes |
18:05 | <ljharb> | shu: it's a bit easier to polyfill etc this way also, but that's a lesser concern since it's already a thing |
18:05 | <shu> | ljharb: is it? wouldn't it be harder? |
18:05 | <shu> | what if e.g. SharedArrayBuffer didn't exist? (SABs aren't polyfillable but suppose they were) |
18:06 | <ljharb> | then i'd be able to stick it on ArrayBuffer |
18:06 | <ljharb> | as opposed to having to make a new global, which might conflict with any existing global, etc |
18:06 | <shu> | right, but what if you also needed to make the new global? |
18:06 | <ljharb> | then i'm no worse off |
18:06 | <ljharb> | (than with SAB) |
18:06 | <Bakkot> | is this rgn talking? |
18:06 | <ljharb> | i agree it's a minimal difference ofc, which is why it's very secondary to "organizational" |
18:07 | <ljharb> | Bakkot: it's rick button |
18:07 | <ljharb> | Bakkot: not sure the acronym |
18:07 | <rricard> | rbu |
18:07 | <Bakkot> | sorry, thanks |
18:07 | <shu> | ljharb: i was thinking it's worse off than existing because for 2 different globals, their polyfills would compose naturally and just work |
18:07 | <shu> | ljharb: but if they're nested, there's more coordination |
18:09 | <Bakkot> | i have to stop notes |
18:09 | <Bakkot> | poo ^ |
18:09 | <ljharb> | shu: i think it's the same that way |
18:11 | <shu> | ljharb: okay, i think high order bit for me is i do not want to spend any more time on this |
18:11 | <Bakkot> | same as yesterday I gotta got AFK the rest of the meeting but will leave the bot running, sorry if it dies |
18:14 | <shu> | ljharb: i think i'll withdraw my opinion and just ask for Stage 3 with namespaced -- barring possible objections from the other side, of course |
18:14 | <ljharb> | shu: i think moddable's claim is stronger than mine; if not for that i'd be willing to go with globals. just ftr. |
18:15 | <shu> | understood |
18:15 | <rkirsling> | anybody hearing an intermittent pop on the audio? |
18:16 | <shu> | when nobody was speaking earlier i was hearing a weird warble, but it's fine when someone is speaking |
18:16 | <michaelficarra> | is this just proposing to shorten {}.hasOwnProperty.call to Object.has? |
18:16 | <shu> | michaelficarra: yeah, afaict |
18:16 | <ljharb> | yes |
18:16 | <shu> | michaelficarra: it's useful for null-proto things |
18:16 | <michaelficarra> | are we going to do Object.toString next? |
18:17 | <ljharb> | if Symbol.toStringTag hadn't made it useless, i'd say maybe :-p |
18:17 | <michaelficarra> | shu: it's not, both of those work on null-proto things |
18:17 | <devsnek> | can we get stage 2 on this |
18:17 | <devsnek> | it has spec text |
18:17 | <shu> | michaelficarra: you don't think it's useful to be able to type Object.has vs `{}.hasOwnProperty.call`? |
18:17 | <shu> | especially with understanding `call` semantics? |
18:18 | <michaelficarra> | shu: not really? they're almost identical |
18:18 | <ljharb> | also `Object.prototype.hasOwnProperty.call` versus `{}.hasOwnProperty.call` is a thing |
18:18 | <jridgewell> | I've found beginners are not comfortable (or don't know how) to do `Object.prototype.hasOwnProperty.call` |
18:18 | <ljharb> | this would provide one nice, short, static method |
18:18 | <shu> | i'm pretty positive on this despite its being an alias, yeh |
18:18 | <shu> | yeah* |
18:18 | <michaelficarra> | also, hasOwnProperty says "own" in the name, whereas I would assume Object.has had "in" semantics |
18:18 | <devsnek> | maybe we can name it hasOwn |
18:18 | <shu> | yes, i think i would prefer hasOwn vs has |
18:19 | <rbuckton> | ``` |
18:19 | <rbuckton> | const uncurryThis = Function.prototype.bind.bind(Function.prototype.call); |
18:19 | <rbuckton> | const hasOwn = uncurryThis(Object.prototype.hasOwnProperty); |
18:19 | <rbuckton> | hasOwn({ a: 1 }, "a"); // true |
18:19 | <rbuckton> | ``` |
18:19 | <ljharb> | either has or hasOwn works fine for me |
18:19 | <ljharb> | rbuckton: `Function.bind.call(Object.prototype.hasOwnProperty)` is a bit shorter :-p |
18:19 | <ystartsev> | +1 to the general discussion -- one thing we were also discussing was the proxy has trap, and reflector.hass |
18:19 | <ljharb> | rbuckton: but yes, that's exactly what the `has` package does |
18:19 | <ystartsev> | as potentially confusing bits |
18:19 | <rbuckton> | Yeah, but I use `uncurryThis` quite a bit :) |
18:20 | <ljharb> | rbuckton: https://npmjs.com/call-bind is what all my packages use for that |
18:20 | <robpalme> | we will need to educate people on Object.has vs Reflect.has |
18:20 | <ljharb> | robpalme: you're assuming anyone knows about Reflect.has |
18:21 | <michaelficarra> | does Reflect.has have `in` semantics? |
18:21 | <ystartsev> | yes |
18:21 | <rbuckton> | I think `hasOwn` is my preference, for the same reasoning as ystartsev. `Object.getOwnPropertyDescriptor -> Reflect.getOwnPropertyDescriptor` so `Object.has -> Reflect.has`. Going with `hasOwn` is less confusing. |
18:21 | <devsnek> | meanwhile in node https://gc.gy/86647883.png |
18:21 | <robpalme> | I agree with @rbuckton, but it's a mild feeling |
18:22 | <michaelficarra> | devsnek: basically the first few lines of every JS program I write |
18:22 | <devsnek> | currying > use strict |
18:22 | <rbuckton> | `Object.(keys|values|entries)` returns arrays while `(Map|Set).(keys|values|entries)` returns an iterator, so its not a 1:1 comparison. |
18:26 | <michaelficarra> | jridgewell: FWIW I pull things off Object.prototype with {}, Array.prototype with [], and Function.prototype with Date |
18:27 | <rbuckton> | "and Function.prototype with Date"... wat? |
18:27 | <devsnek> | can we ask for stage 4 |
18:27 | <michaelficarra> | don't judge |
18:27 | <rbuckton> | lol |
18:27 | <ljharb> | lol |
18:27 | <devsnek> | date is always available, unlike `function() {}` |
18:28 | <rbuckton> | You can always pull `hasOwnProperty` off of `Object`, though it will do a prototype walk to get to it :) |
18:28 | <rbuckton> | `Object.hasOwnProperty.call(obj, key)` |
18:28 | <ljharb> | that's why we can't name this `Object.hasOwnProperty` :-p |
18:29 | <shu> | Object.hasOwnProperty2 |
18:29 | <ljharb> | ship it |
18:29 | <ystartsev> | +1 |
18:29 | <rbuckton> | Very true. Not sure I have a major preference of `has` vs `hasOwn`, but still prefer `hasOwn`. |
18:30 | <ystartsev> | if hasOwn isn't a web compat risk, i think it is a good choie |
18:30 | <shu> | i think the analogy with collections is very weak |
18:30 | <ljharb> | problem: "i need an ergonomic way to check if an object has an own property" |
18:30 | <shu> | ownness doesn't matter for collections |
18:30 | <rbuckton> | shu: +1 |
18:31 | <TabAtkins> | I'm just super in favor of anything that moves these awkward Object.prototype things to less awkward locations. |
18:31 | <ljharb> | same |
18:31 | <ystartsev> | +1 to the point about the problem statement that michaelficarra just brought up |
18:32 | <rbuckton> | qq: Earlier it was mentioned that built-in modules essentially died on the vine. Was the proposal officially withdrawn, or is it just stale? |
18:32 | <bradleymeck> | rbuckton: indefinitely stalled / push back against both reserving specifiers from web and using new syntax from various |
18:33 | <bradleymeck> | likely could move somewhat if we could resolve either of those |
18:33 | <bradleymeck> | but last I heard about this was from msaboff |
18:34 | <msaboff> | Stale |
18:34 | <shu> | there's a more fundamental disagreement for built-in modules: it bifurcates the ecosystem |
18:34 | <rbuckton> | I still kind of wish we had the ability to do something like `import { Object } from <builtins>` or `import { ResizableArrayBuffer } from <collections>` from both the _Script_ and _Module_ goals. |
18:34 | <devsnek> | pattern matching woooo |
18:35 | <msaboff> | rbuckton Me too. |
18:35 | <ryzokuken> | terminator is championing this proposal |
18:35 | <devsnek> | `echo "export const Object = globalThis.object" > './<builtins>'` |
18:36 | <bradleymeck> | why don't we propose static `import` from Script like Allen said a few years ago, just ban `async` flagged graphs like service workers do |
18:36 | <ystartsev> | bradleymeck: we had some discussion about that |
18:36 | <devsnek> | i'm strongly against anything that disables async graphs |
18:36 | <rbuckton> | That's different when not in a frozen realm where someone can do `Object = function () {}`, or as a way to avoid the concerns Moddable had about introducing new globals. |
18:36 | <devsnek> | service workers are bad enough |
18:40 | <bradleymeck> | rbuckton: node goes *REALLY* far to deal w/ doing essentially that with our `primordials` |
18:40 | <bradleymeck> | like the uncurryThis snippet devsnek pasted |
18:41 | <michaelficarra> | I smell a new protocol for matching :-) |
18:42 | <devsnek> | michaelficarra: where the first class protocols at |
18:42 | <ljharb> | michaelficarra: good nose |
18:43 | <rkirsling> | the phrase "avoiding footguns" was literally used, what |
18:43 | <rbuckton> | `Function.prototype.uncurryThis` |
18:43 | <ljharb> | i think wsdferdksl1 is reading ahead |
18:43 | <michaelficarra> | devsnek: :'( I need to spend time on it |
18:43 | <bradleymeck> | rbuckton that is infuriating |
18:44 | <littledan> | The presentation of goals here was excellent |
18:44 | <bradleymeck> | you would have to bind uncurryThis to uncurryThis |
18:44 | <devsnek> | i dislike this syntax |
18:44 | <devsnek> | but i like pattern matching |
18:44 | <rbuckton> | bradleymeck: can't tell if joking or serious? I'm joking, tbh. |
18:45 | bradleymeck | cries |
18:45 | <bradleymeck> | i do want uncurryThis tho |
18:45 | <bradleymeck> | TS does not like that fn |
18:45 | <bradleymeck> | just to get support for it |
18:45 | <rbuckton> | bradleymeck: `const uncurryThis: <T, A extends any[], R>(f: (this: T, ...args: A) => R) => (this_: T, ...args: A) => R = Function.prototype.bind.bind(Function.prototype.call);` |
18:46 | <rbuckton> | Doesn't work with overloaded signatures though. |
18:47 | <devsnek> | having to type `when (...)` makes me angry |
18:47 | <bradleymeck> | why? |
18:47 | <devsnek> | just let me type the `...` |
18:47 | <rbuckton> | bradleymeck: `Function.prototype.uncurryThis` would have been something like `const hasOwn = Object.prototype.hasOwn.uncurryThis()`, the alternative would be `const hasOwn = Function.uncurryThis(Object.prototype.hasOwnProperty)` |
18:47 | <ljharb> | devsnek: it's needed, keep watching |
18:47 | <devsnek> | ljharb: did smth change since our last convo |
18:47 | <ljharb> | devsnek: probably |
18:48 | <ljharb> | devsnek: the last month's been busy |
18:48 | <bradleymeck> | rbuckton we do a different signature that does a little better https://github.com/nodejs/node/blob/master/typings/primordials.d.ts#L1 , but yea it is still pretty unhappy usually |
18:48 | <devsnek> | i think we should ensure that the common case doesn't have extra syntax |
18:48 | <bradleymeck> | rbuckton: yea, that would let us more sanely do some stuff w/o deopts is the hope |
18:48 | <ljharb> | devsnek: that's certainly a goal |
18:49 | <rbuckton> | bradleymeck: Improving support for handling function signatures in type-space is something I'm experimenting with. |
18:51 | <rbuckton> | Do patterns allow arbitrary expressions, like `when (["go", fn()]) { ... }`? The `as` clause will be tricky for TypeScript, since we use that in expression positions to do type assertions |
18:52 | <ljharb> | rbuckton: wait a slide or two |
18:52 | <ljharb> | rbuckton: p sure it should be fine with TS |
18:52 | <devsnek> | worst case you can release typescript 3 |
18:52 | <ljharb> | 4? |
18:52 | <rbuckton> | We're on TS 4 already :) |
18:52 | <devsnek> | oh |
18:52 | <devsnek> | typescript 5 then |
18:53 | <michaelficarra> | regexps don't need a special case if the returned value from the protocol describes the introduced bindings |
18:53 | <ljharb> | michaelficarra: true |
18:53 | <devsnek> | michaelficarra: i don't think engines would like that |
18:53 | <bradleymeck> | no dynamic scope bindings |
18:53 | <ljharb> | michaelficarra: but in that case, the returned value would be the match object |
18:53 | <ljharb> | this isn't dynamic, the capture group names are static |
18:53 | <rbuckton> | And we've already changed our assertion syntax once. `<X>a` originally (and still), but `a as X` as well (since the `<X>a` syntax conflicted with JSX). |
18:53 | <devsnek> | ljharb: the return value is dynamic |
18:53 | <ljharb> | michaelficarra: which means you'd have to do `as { groups: { a, b } }` to get the bindings |
18:53 | <TabAtkins> | Yeah we're pretty explicitly agaisnt the user-defined stuff implicitly introducing bindings. Bindings need to be visible from source. |
18:53 | <ljharb> | devsnek: right but the literal pattern form is special, not a regex object |
18:54 | <devsnek> | agree with tab here |
18:54 | <ljharb> | rbuckton: so for this concern, it'd be `^(x as y)` and should work fine |
18:54 | <ljharb> | devsnek: with a regex object, bindings *only ever* come from an explicit `as` |
18:54 | <devsnek> | hm |
18:55 | <devsnek> | i thought they came from the group names |
18:55 | <ljharb> | devsnek: only in the literal pattern form |
18:55 | <ljharb> | in no way would we try to introduce magic implicit bindings :-) |
18:55 | <devsnek> | oh i see what you're saying |
18:55 | <rbuckton> | Also concerned about `^`, since I'm still a fan of `^x` creating an index object that can be used in arrays (which I believe was presented last meeting). |
18:55 | <ljharb> | it's an open question tho, we don't have to have that sugar for the literal pattern form. |
18:55 | <devsnek> | makes more sense now |
18:55 | <devsnek> | we should 100% have that sugar |
18:55 | <ljharb> | rbuckton: happy to bikeshed that operator |
18:55 | <michaelficarra> | this presentation is very nice :-) |
18:55 | <ljharb> | devsnek: 👍 |
18:56 | <rkirsling> | michaelficarra: 🎉 |
18:56 | <devsnek> | still against when() though |
18:56 | <rbuckton> | But it seems to be unique enough, though if both existed you might have a `when ^^1` :) |
18:56 | <ljharb> | rbuckton: lol true, it wouldn't conflict except conceptually. altho you'd need `^(^1)` |
18:56 | <ljharb> | rbuckton: `^` is only allowed with an identifier, or a parenthesized expression |
18:56 | <rbuckton> | I see. |
18:57 | <rkirsling> | good clarification |
18:57 | <devsnek> | ljharb: i didn't see anything saying why when has to exist |
18:57 | <devsnek> | maybe i'm horrible at listening |
18:58 | <ljharb> | devsnek: hm, i guess i was thinking the `if` and `else` headers. but since we came up with `^` i guess we could go straight into the pattern |
18:58 | <ljharb> | devsnek: it does seem nice to me to have a syntactic marker tho |
18:58 | <devsnek> | i'll put a topic |
18:58 | <ljharb> | devsnek: without that, we'd have to require `;` between clauses, or have ASI kick in |
18:58 | <rbuckton> | ljharb: In general I like this proposal. I've been thinking more about Rust-style ADT enums (I still have that `enum` proposal I may eventually bring to committee), and how that could work with pattern matching. |
18:58 | <devsnek> | multiple clauses on the same line should never exist |
18:59 | <michaelficarra> | rbuckton: I really hope that enum proposal is nothing like TypeScript enums anymore |
19:00 | <TabAtkins> | I really really hate the idea of relying on array holes to avoid the need for a nil matcher. :( |
19:00 | <michaelficarra> | I think the catch integration should be a follow-on proposal |
19:00 | <rbuckton> | michaelficarra: Anything I put together will need to support a number of scenarios, including the ones in TS. Even if the default behavior is creating symbol-valued properties for JS, I still want to be able to create number-valued properties. |
19:00 | <rkirsling> | 5 minutes oof |
19:01 | <ljharb> | michaelficarra: yes, definitely |
19:01 | <devsnek> | why does logical or use `|` in patterns |
19:01 | <devsnek> | could it not just be || |
19:01 | <rkirsling> | I do agree that ^ is the least intuitive part but I haven't thought of a better alternative |
19:02 | <michaelficarra> | the concept of pinning is pretty crucial for this proposal though so we'll need to figure out something |
19:02 | <rkirsling> | devsnek: that's the norm in other languages; it's only a "logical" OR if you analogize with an existing conditional, but here it's really a "separator for alternatively" |
19:02 | <devsnek> | i wish rust had pinning |
19:02 | <rkirsling> | *alternatives |
19:02 | <akirose> | i accidentally deleted the next person on the queue |
19:03 | <TabAtkins> | devsnek: No particular reason |
19:03 | <rkirsling> | (for that reason, I'd probably prefer that we not say "logical" OR) |
19:03 | <devsnek> | 🤷🏻 |
19:03 | <ljharb> | brad4d: no, absolutely not |
19:03 | <ljharb> | brad4d: if you want the brittle instanceof you have to type that yourself, or add the protocol to your class to provide it |
19:04 | <rkirsling> | words aside, `||` would be problematic precisely because the disjuncts *aren't* boolean |
19:04 | <michaelficarra> | oh the strictness with object matching seems to motivate a rest form without a binding |
19:04 | <rbuckton> | My earliest version of the `enum` proposal actually introduced a new value type that had both a name and a value (similar to C# enums), so that they are essentially unique: |
19:04 | <rbuckton> | ``` |
19:04 | <rbuckton> | enum Color { Red }; |
19:04 | <rbuckton> | enum Animal { Dog }; |
19:04 | <rbuckton> | Color.Red === Animal.Dog; // false |
19:04 | <rbuckton> | Number(Color.Red) === Number(Color.Dog); // true |
19:04 | <rbuckton> | Number(Color.Red); // 0 |
19:04 | <rbuckton> | String(Color.Red); // "Red" |
19:04 | <rbuckton> | typeof Color.Red; // "enum" |
19:04 | <rbuckton> | ``` |
19:04 | <rbuckton> | However I was concerned introducing a new value type and typeof tag would be too difficult to advance. |
19:05 | <devsnek> | how about "or" as a keyword |
19:05 | <rkirsling> | sure, that'd be an option |
19:08 | <TabAtkins> | michaelficarra: What do you mean? |
19:14 | <brad4d> | ljharb: I asked because one of the example seemed to imply that `AggregateError` would have such a static property. |
19:15 | <rbuckton> | ljharb: `as` may be fine in that context (though possibly confusing for TS users), but I'm curious if you've considered anything like https://www.python.org/dev/peps/pep-0572/ (using the `:=` operator to introduce a binding). Granted, Python introduced `:=` because of how variables work in that language, so its not a direct comparison. |
19:16 | <rkirsling> | rbuckton: I think that's directionally problematic |
19:16 | <rbuckton> | "directionally problematic"? |
19:17 | <rkirsling> | it's an afterthought, like "and we need to be able to refer to it as" |
19:17 | <rbuckton> | Not if you reclassify it the statement to "and we need to be able to restrict it to" |
19:19 | <rbuckton> | ``` |
19:19 | <rbuckton> | // start with |
19:19 | <rbuckton> | when (["go", dir]) { ... } // dir in scope |
19:19 | <rbuckton> | // add restriction |
19:19 | <rbuckton> | when (["go", dir := ("N" | "S" | "E" | "W")]) { ... } // dir in scope |
19:19 | <rbuckton> | // alternative, use a keyword like 'is' |
19:19 | <rbuckton> | when (["go", dir is ("N" | "S" | "E" | "W")]) { ... } // dir in scope |
19:19 | <rbuckton> | ``` |
19:21 | <rbuckton> | My concerns about `as` may be unfounded, I'll have to check the repo after the changes ljharb have mentioned are merged to reflect the current state. |
19:24 | <rbuckton> | I'm a little concerned about `match (x)` though, since you either need an NLT between `)` and `{`, or a massive cover grammar, and that pushes people towards a specific style (brace on same-line vs brace on next line). That's why I'd switched `using (x) {` to match Java's `try using (x) {`. |
19:24 | <rkirsling> | yeah, I feel like putting the binding name first makes it look like an unconditional pattern match, since the "restriction" there is just a normal pattern match and not a guard |
19:24 | <ljharb> | rbuckton: we'd use an NLT. nobody uses allman |
19:25 | <rbuckton> | I seem to recall that being a concern for `using (x) {}` a few years back. |
19:31 | <rbuckton> | If pattern matching moves forward with `match ( Expression ) [no LineTerminator here] MatchBlock`, maybe I'll switch `using` back. For `using`, there were always two cases I wanted to support. One that introduced bindings, and one that didnt. |
19:31 | <rbuckton> | I've been thinking of dropping `try using` in favor of `using const x = ...`, but haven't been happy with `using value Expression`, so maybe I just do `using const x = ...` (block scoped binding) and `using ( Expression ) [NLT] { ... }` (block-lifetime for expression). |
19:35 | <ljharb> | rbuckton: `as` is consistent with named imports/exports tho |
19:39 | <rbuckton> | But inconsistent with destructuring. I can understand `as` in imports though, since the bindings are "live", but we could have just done `import { x: y } from "foo"`. I've seen that some of the CommonJS ecosystem does `const { x: y } = require("foo")` when not using a module transpiler. Is the binding in a match "live" as well, or is it just a copy of the matched value? |
19:40 | <rbuckton> | Oh, ljharb: Any chance `browserify/resolve` will get support for NodeJS export maps? I was just moving a project over to using them but ran into Jest not supporting them because they're waiting on `resolve`. Currently I'm trying to implement my own custom resolver for Jest to work around the issue. |
19:46 | <Bakkot> | ugh I am not enthusiastic about the idea of a new cover grammar |
19:57 | <ljharb> | akirose: bnb: robpalme we forgot to get reviewers for Object.hasOwn, can we do that first thing tomorrow? i'll volunteer to be one of them |
19:57 | <ljharb> | rbuckton: tbh i think the real thing that sucks is that object destructuring used `:` instead of `as` |
19:58 | <ljharb> | rbuckton: it's not live, just like destructuring isn't |
19:58 | <ljharb> | rbuckton: as for `using` i'm personally fine with an NLT; if we decide we can't do that, then all new keywords are off limits, and the only people hurt by it are using a brace style that causes bugs in JS and that all style guides and common linters discourage |
20:01 | <rbuckton> | Bad idea: introduce a trailing `\` for anyone who *really* wants braces on a new line: |
20:01 | <rbuckton> | ``` |
20:01 | <rbuckton> | match (x)\ |
20:01 | <rbuckton> | { |
20:01 | <rbuckton> | } |
20:01 | <rbuckton> | ``` |
20:01 | <TabAtkins> | yeah if object destructing used `as` it would make me much happier in match() |
20:09 | <ljharb> | rbuckton: i thought shitposts were supposed to go in tdz :-p |
20:10 | <rbuckton> | Not a shitpost, just a bad idea. |
20:10 | <ljharb> | :-p |
20:11 | <ljharb> | if they didn't need that for `return \` then they don't need it ¯\_(ツ)_/¯ |
20:11 | <rbuckton> | I mean, this works: |
20:11 | <rbuckton> | ``` |
20:11 | <rbuckton> | let x = "a\ |
20:11 | <rbuckton> | b"; |
20:11 | <rbuckton> | x; // "ab" |
20:11 | <rbuckton> | x.length; // 2 |
20:11 | <rbuckton> | ``` |
20:29 | <michaelficarra> | TabAtkins: it sounds like the object matching makes an exhaustiveness assertion which you can disable by adding a rest binding |
20:30 | <michaelficarra> | but if you don't want that, I imagine you would just add a `...`? |
20:30 | <TabAtkins> | No, object matching is explicitly non-exhaustive |
20:30 | <TabAtkins> | array matching is exhaustive |
20:30 | <michaelficarra> | oh, I misunderstood that part of the presentation then |
20:30 | <michaelficarra> | okay |
20:30 | <TabAtkins> | (exhaustive object matching would be unusable from the get-go, as you'd need to include, at minimum, all the Object.prototype properties in every pattern) |
20:30 | <michaelficarra> | or just put a … to switch the behaviour |
20:31 | <TabAtkins> | What I mean is that you'd need to put that in *every* pattern, because you'd *never* want an exhaustive match. |
20:31 | <michaelficarra> | fair |
20:56 | <mpcsh> | late to all this but yeah I think I could be swayed to have arrays be non-exhaustive for consistency's sake, but objects definitely have to be non-exhaustive |
20:56 | <mpcsh> | although I do definitely think the most intuitive version is arrays are exhaustive, objects are not |
20:57 | <mpcsh> | it's inconsistent, yes, but it best models what folks will try to do. being able to express "an array of exactly this length and give me these bindings" is very powerful |
20:59 | <ljharb> | array and object destructuring are already similarly inconsistent around trying to destructure nullish values |
20:59 | <ljharb> | and they both make perfect sense in isolation |
21:10 | <TabAtkins> | I *really* don't think we can make arrays non-exhaustive. It would clash with author's expectations *so hard* |
21:27 | <mpcsh> | I don't know if I agree that it's such a hard clash - `const [a, b] = [1, 2, 3, 4]` works. I think the better argument is the expressiveness that non-exhaustive matching enables |
21:29 | <ljharb> | i could go either way on it |
21:29 | <ljharb> | if it's non-exhaustive, you *can* do `[…rest] & { length: 2 } & [a, b]` but i don't think you can go the other way as easily? |
21:35 | <mpcsh> | eugh, that's pretty gross |
21:35 | <mpcsh> | and requires `&` at the outset |
21:36 | <rbuckton> | Could reuse tuple syntax for exhaustive arrays, since tuples have a fixed length? Unless you wanted to reserve `#[]` to explicitly match *only* tuples. |
21:37 | <rbuckton> | `when (#[a, b]) { ... }` |
21:38 | <rbuckton> | though that's only a few characters shorter than `when([a, b, ...]) { ... }`, so ¯\_(ツ)_/¯ |
21:38 | <mpcsh> | we'd probably want `#[]` to only match tuples, yeah |
21:39 | <rbuckton> | Would `[]` only match arrays then? I'd want to be able to match either... |
21:42 | <mpcsh> | hm, I think that's probably a question for the record & tuple folks. my intuition would be they're both exclusive and if you want both you can do `[a, b] | #[a, b]`, or write a custom class with the match protocol method we presented |
21:44 | <ljharb> | mpcsh: indeed, it is gross. but it's at least possible. |
21:44 | <ljharb> | rbuckton: tuples are primitives, arrays aren't |
21:45 | <ljharb> | `[ ]` is destructuring. `#[]` is just like `3` |
21:45 | <ljharb> | so `#[a, b]` Just Works using `===` |
21:45 | <ljharb> | (with extra magic needed for the bindings, ofc) |
21:45 | <rbuckton> | I take it `|` shortcuts? It's odd to see the same binding identifier repeated. |
21:46 | <rbuckton> | It is a bit odd to see `|` and `&` used for this (even though its similar to how TypeScript uses them in type-space for unions/intersections). |
21:46 | <ljharb> | yes, it's "or" semantics |
21:48 | <ljharb> | how we spell the combinators or the pin operator is certainly bikesheddable |
21:48 | <ljharb> | but i haven't heard any suggestions that make _more_ sense to me yet |
21:52 | <rbuckton> | Is `^` only `Identifier` or `ParenthesizedExpression`? |
21:53 | <rbuckton> | (roughly) |
21:53 | <ljharb> | actually we'd talked about it also including chains and CallExpressions |
21:53 | <rbuckton> | I'm sure people will want to do this: |
21:53 | <rbuckton> | ``` |
21:53 | <rbuckton> | import * as foo from "foo"; |
21:53 | <rbuckton> | match (x) { |
21:53 | <rbuckton> | when ^foo.Class { ... } |
21:53 | <rbuckton> | } |
21:53 | <rbuckton> | ``` |
21:53 | <ljharb> | right, with chains that'd work fine |
21:53 | <rbuckton> | Could always use a similar restricted grammar as decorators. |
21:54 | <ljharb> | conceptually i think it should work bare with "one thing" and with parens with "multiple things" |
21:54 | <rbuckton> | Anything more complex needs `()`. |
21:54 | <ljharb> | yeah presumably pattern matching and decorators would share the same syntax limits there |
21:56 | <rbuckton> | You could also use a different clause name than `when` for expression matchers, or a keyphrase like `when is` rather than an esoteric `^`. |
21:56 | <ljharb> | the expression stuff needs to be nestable |
21:57 | <ljharb> | so if it's a keyword, you'd get into super awkward precedence/paren things like `await` has |
21:57 | <ljharb> | that's why we ended up leaning towards a sigil |
21:58 | <mpcsh> | (and just spelling `when` differently doesn't nest) |
21:58 | <rbuckton> | Isn't it `when (Pattern) {}` anyways? How would `is` have a precedence issue? |
21:58 | <ljharb> | rbuckton: a pattern has to be able to have "an expression" at any level tho |
21:58 | <ljharb> | rbuckton: like `{ a: { b: { c: [a, b, ^c] } } } }` |
21:59 | <rbuckton> | I see. |
21:59 | <ljharb> | rbuckton: that'd be `[a, b, when c]`, but if `c` is a parenthesized one, it gets weirder |
21:59 | <ljharb> | and forcing parens with a keyword is also weird. |
22:00 | <ljharb> | (open to ideas ofc, just that's the thought process e went through) |
22:00 | <ljharb> | *we |
22:01 | <rbuckton> | If expressions are nestable, why have the headless form `when ^Name {}` and not just `when (^Name) {}` for consistency? |
22:01 | <ljharb> | we could, just seemed like nice sugar |
22:02 | <ljharb> | `when (^Name)` would still work regardless |
22:02 | <ljharb> | but `when (^(…))` looks worse than `when ^(…)` ¯\_(ツ)_/¯ |
22:07 | <rbuckton> | I'm a bit wary of the parenless form only because it reduces syntax space for any possible future extensions to the `when` clause (of which we may have none yet, but look at where ASI has lead us). |
22:08 | <ljharb> | devsnek suggested we get rid of the `when` entirely |
22:08 | <rbuckton> | I really like the proposal. A few things make me squeamish though (like the `with` keyword) |
22:08 | <ljharb> | so it'd just be `^Name { }` or `^(<expr>) {}` or `(<pattern>) {}` |
22:08 | <ljharb> | rbuckton: yeah i _really_ don't like spelling it "with" |
22:09 | <rbuckton> | That's odd with the `if` and `else` clauses though |
22:09 | <ljharb> | yeah that's a reasonable counter to "remove `when`", to be sure |
22:09 | <ljharb> | i _do_ like how `when` and `else` are the same length, so they all line up in oneliners :-p |
22:10 | <ljharb> | one of the complaints i hear a lot about let/const is that they're not all 3 letters |
22:10 | <rbuckton> | Then again, PowerShell does interesting things in its `switch` clause that are similar: |
22:10 | <rbuckton> | ``` |
22:10 | <rbuckton> | switch ($x) { |
22:10 | <rbuckton> | Foo { ... } # Foo interpreted as "Foo" |
22:10 | <rbuckton> | Bar { ... } # Bar interpreted as "Bar" |
22:10 | <rbuckton> | {$_ -gt 3} { ... } # ScriptBlock with $_ topic variable |
22:10 | <rbuckton> | } |
22:10 | <rbuckton> | ``` |
22:13 | <rbuckton> | Almost want to use `as` instead of `with`. Or `into`. |
22:13 | <ljharb> | pretty sure we can pick anything we want since it's not an expression space |
22:14 | <rbuckton> | I was tinkering with a LINQ-like comprehension syntax for JS that used `into` as a keyword: |
22:14 | <rbuckton> | ``` |
22:14 | <rbuckton> | const x = |
22:14 | <rbuckton> | from user of users |
22:14 | <rbuckton> | select user.name into name |
22:15 | <rbuckton> | where name !== "Bob" |
22:15 | <rbuckton> | select name; |
22:15 | <rbuckton> | ``` |
22:15 | <rbuckton> | or invert the clause: |
22:15 | <rbuckton> | ``` |
22:15 | <rbuckton> | when [first, last] from ^Name { ... } |
22:15 | <rbuckton> | ``` |
22:16 | <rbuckton> | which matches the right-to-left reading-order of the underlying array destructuring :`const [first, last] = Name[Symbol.matcher](x)` |
22:18 | <rbuckton> | Or just chain whens like `when ^Name when [first, last] { ... }` (since `^Name` produces a new object to match, that you might even want to further reduce) |
22:20 | <rbuckton> | More verbose, but a deeper nesting might allow something like: |
22:20 | <rbuckton> | ``` |
22:20 | <rbuckton> | match (...) { |
22:20 | <rbuckton> | when ^Name match { |
22:20 | <rbuckton> | when (["foo", bar]) { |
22:20 | <rbuckton> | } |
22:20 | <rbuckton> | when ([first, last]) { |
22:20 | <rbuckton> | } |
22:20 | <rbuckton> | } |
22:20 | <rbuckton> | } |
22:20 | <rbuckton> | ``` |
22:25 | <rbuckton> | Or, if you prefer sigils, maybe use an indirection like `when ^Name -> [first, last] { }`. |
22:25 | <rbuckton> | Generally I think I like `into` since you could consider it as taking the return value of one match and passing it into another pattern: |
22:25 | <rbuckton> | ``` |
22:25 | <rbuckton> | match (...) { |
22:25 | <rbuckton> | when ^Name into { firstName, lastName } { ... } // result must have `firstName` and `lastName` properties. |
22:25 | <rbuckton> | } |
22:25 | <rbuckton> | ``` |
22:25 | <rbuckton> | The only value `with` has is that its a keyword. Unfortunately one with a bad rep. |
22:32 | <rbuckton> | One last thought, then I'll stop bugging you about the proposal. The current explainer uses `->` into an expression context, but the new version uses "implicit 'do' blocks". That's probably fine for most expressions, but its going to be cumbersome for returning object literals: |
22:32 | <rbuckton> | ``` |
22:32 | <rbuckton> | const x = match(y) { |
22:32 | <rbuckton> | when ({ z }) { [z] } // array |
22:32 | <rbuckton> | when ({ w }) { ({ w }) } // object |
22:32 | <rbuckton> | }; |
22:32 | <rbuckton> | ``` |
22:32 | <rbuckton> | vs. |
22:32 | <rbuckton> | ``` |
22:32 | <rbuckton> | const x = match (y) { |
22:33 | <rbuckton> | when ({ z }) -> [z] |
22:33 | <rbuckton> | when ({ w }) -> {w} |
22:33 | <rbuckton> | }; |
22:33 | <rbuckton> | ``` |
22:36 | <rbuckton> | I think it may catch some users off-guard. Makes me feel the cost savings of `when (^Name)` vs `when ^Name` don't quite cover the complexity of `{ ({ x }) }` :/ |
22:49 | <ljharb> | that's already true for `do` expressions tho, right? |
22:49 | <rbuckton> | Yeah, but `do` expressions have a specific use case, where you use them *because* you need a statement context. A lot of use cases for `match` are in expressions and you may not need a statement context, but one is forced on you. |
22:50 | <TabAtkins> | rbuckton: The `into` keyword works for me if `with` is a no-go spelling. ^_^ |
22:50 | <TabAtkins> | Not happy with the inverted order of your `from` example, I think it makes things *less* clear, since execution order actually jumps around |
22:50 | <rbuckton> | `with` isn't no-go, its just... well, `with`. |
22:50 | <TabAtkins> | Right. |
22:50 | <TabAtkins> | I didn't mean no-go from a parsing standpoint, just from an acceptability standpoint. |
22:50 | <TabAtkins> | It just happens to be how I first spelled it in my proposal. |
22:51 | <TabAtkins> | But I actually kinda like the implicit meaning of `into` better |
22:51 | <TabAtkins> | for the reason you gave above |
22:51 | <rbuckton> | I wouldn't block on it using `with`, it just has that "there be dragons" feel to it |
22:52 | <TabAtkins> | also, re: your issue about returning object literals, yeah, i feel you |
22:53 | <TabAtkins> | I'd be fine with just having the RHS be an expression, and relying on literal do-blocks when you need more. That was in an earlier version, I assume Jordan/Mark swapped it out for taste earlier. |
22:53 | <rbuckton> | `match` is just a better `?:` right (/s)? why not use `:` for expression-only, and `{}` for implicit `do` :) |
22:53 | <ljharb> | rbuckton: i'll have on the repo an "enhancement" we could do where the RHS can just be a bare expression |
22:54 | <ljharb> | the reason we removed the `do` is because it would encourage people to do `async do` there, and have match expressions that only sometimes return a promise |
22:55 | <ljharb> | we could do `when (…) <expr>` and `when (…) do { … }` and then let `async match` upgrade all the `do`s to `async do`s, i suppose |
22:55 | <rbuckton> | ``` |
22:55 | <rbuckton> | const x = match(y) { |
22:55 | <rbuckton> | when ({ z }): [z] |
22:55 | <rbuckton> | when ({ w }): { w } |
22:55 | <rbuckton> | when ({ v }) { |
22:55 | <rbuckton> | // more complex statement-level processing |
22:55 | <rbuckton> | } |
22:55 | <rbuckton> | } |
22:55 | <rbuckton> | ``` |
22:56 | <ljharb> | and for a bare `if`? |
22:56 | <rbuckton> | Heh, consider dropping blocks *and* `when` and you get this: |
22:56 | <rbuckton> | ``` |
22:56 | <rbuckton> | const x = match(y) { |
22:56 | <rbuckton> | ({ z }): [z], // need terminator so as not to interpret next line as call... |
22:56 | <rbuckton> | ({ w }): { w }, |
22:56 | <rbuckton> | ({ v }) { |
22:56 | <rbuckton> | // statements go here |
22:56 | <rbuckton> | } |
22:56 | <rbuckton> | } |
22:56 | <rbuckton> | ``` |
22:56 | <ljharb> | yeah, that seems a bit confusing with object literals |
23:02 | <rbuckton> | ``` |
23:02 | <rbuckton> | const x = match (obj.y) { // what if getter has side-effects |
23:02 | <rbuckton> | if (test(obj.y)): "a", |
23:02 | <rbuckton> | else: "b" |
23:02 | <rbuckton> | }; |
23:02 | <rbuckton> | // vs |
23:02 | <rbuckton> | const x = test(y) ? "a" : "b"; |
23:02 | <rbuckton> | ``` |
23:02 | <rbuckton> | bare `if` feels weird without a topic variable (and I'm not a fan of topic variables), since side-effects are a thing. I'd almost rather do this: |
23:02 | <rbuckton> | ``` |
23:02 | <rbuckton> | const x = match (obj.y) { // what if getter has side-effects |
23:02 | <rbuckton> | when (z) if (test(z)): "a", |
23:02 | <rbuckton> | else: "b" |
23:02 | <rbuckton> | } |
23:02 | <rbuckton> | ``` |
23:04 | <ljharb> | you could do `match (obj.y) as z {` and then `z` is your topic variable |
23:04 | <ljharb> | otherwise it's just "whatever you put in the matchable position", which seems fine to me |
23:05 | <rbuckton> | `match` is interesting in that you can ab^M^Muse it to introduce a temporary binding: |
23:05 | <rbuckton> | ``` |
23:05 | <rbuckton> | const x = match (fn()) { when (y) { y + y } }; |
23:05 | <rbuckton> | // vs |
23:05 | <rbuckton> | const x = do { let y = fn(); y + y; }; |
23:05 | <rbuckton> | ``` |
23:06 | <ljharb> | the latter seems simpler to me |
23:06 | <ljharb> | so i'm not really worried about people doing that |
23:07 | <rbuckton> | I assume each match pattern will evaluate `Get`? This introduces interesting side effects too: |
23:07 | <rbuckton> | ``` |
23:07 | <rbuckton> | const obj = { |
23:07 | <rbuckton> | count: 0, |
23:07 | <rbuckton> | get x() { return ++this.count; }, |
23:07 | <rbuckton> | }; |
23:07 | <rbuckton> | match (obj) { |
23:07 | <rbuckton> | when({ x, y }) { } |
23:07 | <rbuckton> | when({ x, count }) { console.log(count); } // prints: 2 |
23:07 | <rbuckton> | } |
23:07 | <rbuckton> | ``` |
23:08 | <ljharb> | i don't think it has to re-evaluate it |
23:08 | <TabAtkins> | Oh yeah we didn't talk about the `as`-on-matchable part of the grammar |
23:08 | <ljharb> | each clause has to memoize any array-iterator values from the matchable already |
23:08 | <ljharb> | so it seems reasonable to me to memoize the result of the Get too |
23:08 | <ljharb> | to minimize observable operations |
23:10 | <rbuckton> | You can't memoize operations using `^` though, unless you match through a `Proxy` or something, so there's still an (albiet minor?) side-effect hazard there. |
23:11 | <ljharb> | indeed that's true. but i think that would be expected. |
23:11 | <rbuckton> | And you wouldn't want to use a `Proxy` |
23:11 | <ljharb> | most people don't have getter/proxy-based side effects in their program anyways |
23:11 | <rbuckton> | fair. And the `if` clauses can introduce side-effects anyways. |
23:11 | <TabAtkins> | Yeah, and you'd get the same side-effects there with an if-else chain |
23:13 | <rbuckton> | ahem: |
23:13 | <rbuckton> | ``` |
23:13 | <rbuckton> | match (x) { |
23:13 | <rbuckton> | when(/a/) { ... } |
23:13 | <rbuckton> | when(/b/) { ... } |
23:13 | <rbuckton> | } |
23:13 | <rbuckton> | RegExp.$_; // ? |
23:13 | <rbuckton> | ``` |
23:19 | <rbuckton> | Regardless, I'm looking forward to pattern matching. I really do want to spend more time on my `enum` proposal to find something that everyone could agree on, and extend it to ADT-style enums: |
23:19 | <rbuckton> | ``` |
23:19 | <rbuckton> | enum Foo { |
23:19 | <rbuckton> | A, // value |
23:19 | <rbuckton> | B(x, y), // tuple |
23:19 | <rbuckton> | C{ x, y } // record |
23:19 | <rbuckton> | } |
23:19 | <rbuckton> | ... |
23:19 | <rbuckton> | match (value) { |
23:19 | <rbuckton> | when ^Foo.A { ... } |
23:19 | <rbuckton> | when ^Foo.B into [x, y] { ... } |
23:19 | <rbuckton> | when ^Foo.C into {x, y} { ... } |
23:19 | <rbuckton> | } |
23:19 | <rbuckton> | ``` |
23:20 | <rbuckton> | Though I would have preferred a way to do something like this: |
23:20 | <rbuckton> | ``` |
23:20 | <rbuckton> | match (value) { |
23:20 | <rbuckton> | when Foo.A { ... } |
23:20 | <rbuckton> | when Foo.B(x, y) { ... } |
23:20 | <rbuckton> | when Foo.C{x, y} { ... } |
23:20 | <rbuckton> | } |
23:20 | <rbuckton> | ``` |
23:22 | <TabAtkins> | I mean, if it's a language built-in, we can talk |
23:23 | <TabAtkins> | If we've got `-Infinity` in as a literal matcher, we can do other things. |
23:24 | <TabAtkins> | It looks like that would consume the syntax space for dotted stuff, but it might be worthwhile to spend it on that. |
23:26 | <rbuckton> | The biggest complexity of the `enum` proposal is that I need to be sure it supports the constraints that ljharb and michaelficarra have brought to me, while still leaving room for the constraints that TypeScript has. |
23:26 | <rbuckton> | TypeScript needs number-valued enums, and IIRC, ljharb and michaelficarra would prefer Symbol-valued enums. I think its feasible to support both (and other kinds as well), with some kind of default behavior as long as there's a way to override it. |
23:26 | <TabAtkins> | yeah, last time i looked at the enum proposal repo i was fairly happy with the way it allowed for both |
23:27 | <TabAtkins> | iirc just by going off of the first value with an initializer, or something? |
23:27 | <TabAtkins> | or there was some syntax? i forget. it was fine either way |
23:28 | <TabAtkins> | (i know i'd prefer symbol-valued enums by default; type confusion is a hell of a drug) |
23:28 | <rbuckton> | IIRC, in my last conversation with them about the proposal they were adamantly against number-valued enums from even existing, despite the fact that most languages support them and that they have their uses. |
23:28 | <TabAtkins> | oh, we definitely need the ability to ahve them, for bitflags if nothing else |
23:28 | <rbuckton> | It was by going off of an `of` keyword, with a symbol-protocol for handling definitions. |
23:28 | <TabAtkins> | ah yeah, right |
23:35 | <rbuckton> | ``` |
23:35 | <rbuckton> | const enum Color of Symbol { |
23:35 | <rbuckton> | Red, // Symbol(Color.Red) |
23:35 | <rbuckton> | Green, |
23:35 | <rbuckton> | Blue |
23:35 | <rbuckton> | Not sure how much of that made it through :/ |
23:36 | <rbuckton> | and ignore the `const` part. Fingers on autopilot from TypeScript's `const enum` declarations :) |
23:39 | <rbuckton> | Its a bit like Python's enums, with `@@toEnum` serving as `_generate_next_value_`: |
23:39 | <rbuckton> | ``` |
23:39 | <rbuckton> | class Color(Enum): |
23:39 | <rbuckton> | RED = auto() |
23:39 | <rbuckton> | BLUE = auto() |
23:39 | <rbuckton> | GREEN = auto() |
23:39 | <rbuckton> | ``` |
23:39 | <rbuckton> | (and python also has IntEnum, IntFlags) |