16:40 | <rbuckton> | I've posted a PR for the initial spec text for Extractors for possible advancement to Stage 2. I'd appreciate feedback from this group, today if possible, as I plan to merge the PR later today when I post my slides to the agenda. https://github.com/tc39/proposal-extractors/pull/12 |
16:50 | <rbuckton> | In addition, my slides are here if anyone would like to review: https://1drv.ms/p/s!AjgWTO11Fk-TkqpinLRBZZwud0rM9w?e=s7hKoI |
17:20 | <Jack Works> | I have a question |
17:22 | <Jack Works> | Does the extractor proposal encourage this? A custom matcher coerces the subject. Example: const date(yyyy, mm, dd) = 123456789 |
17:23 | <Jack Works> | this is something we don't do in the built-in matchers, which means it is somehow a style we are encouraged for, only test and extract things you own, not something smart |
17:25 | <Jack Works> | if we do something smart (in the pattern matching), things might go like this: when JSON.parse({ x: 1 }) can match the corresponding JSON string and also in the extractor proposal const JSON.parse({ x }) = localStorage.get(...) |
17:28 | <rbuckton> | In general you want an extractor to be the inverse of construction, but Scala (which is the inspiration for this design) explicitly calls out use cases like that. |
17:30 | <rbuckton> | I would say, it's acceptable for users to write user-defined extractors for this purpose, but built-ins generally shouldn't. With the exception being something like RegExp instances, since that is a convenient mechanism to explain how RegExp patterns in pattern matching work, and to allow users to decompose a regexp match pattern into a reusable regexp. |
17:33 | <rbuckton> | if we do something smart (in the pattern matching), things might go like this: JSON.parse as a string can be an arbitrarily large JSON object from which you only intend to extract a fragment, so it has a fairly sizable hidden cost. |
17:33 | <Jack Works> | I wonder if there is any style inconsistency that lives behind, that pattern matching encourages people to write dumb matchers and extractors encourage them to write smart ones. |
17:33 | <Jack Works> | (and they use the same symbol) |
17:34 | <rbuckton> | If we had a SAX-like streaming parser for JSON and the matcher had full knowledge of the nested destructuring graph, maybe it would be possible to implement something efficient. |
17:35 | <rbuckton> | Considering I'm as likely to use extractors for the same reasons in both cases, I don't see a difference between the two. |
17:35 | <ljharb> | wait, why would pattern matching encourage people to write dumb matchers? |
17:37 | <rbuckton> | Though I still don't find the predicate-function capability quite as important. I wonder if it would make sense to only allow predicates in x is y , and not x is y(z) |
17:37 | <Jack Works> | I don't know, maybe because how built-in acts |
17:37 | <Jack Works> | just my personal feeling |
17:39 | <rbuckton> | If and when ADT enums become a thing, and even before that, the 95% use case will be inversion of construction, i.e. Point(let x, let y) = new Point(x, y) . Just like the 95% use case of yield and yield* is for iteration, not coroutine-like generators. |
17:39 | <ljharb> | just my personal feeling |
17:39 | <ljharb> | Though I still don't find the predicate-function capability quite as important. I wonder if it would make sense to only allow predicates in |
17:40 | <ljharb> | but i operate in a subset of the JS ecosystem that basically doesn't use class or new at all outside of builtins |
17:40 | <rbuckton> | I just don't see it. Maybe for a while, but pattern matching leads developers towards a certain style of development that tends to favor instances (or tags) and structure. |
17:41 | <ljharb> | structure certainly. instances, i'm skeptical. |
17:43 | <Jack Works> | that's fine but i still don't understand it, can you elaborate? |
17:43 | <ljharb> | hm, maybe the criteria for your "smart" isn't clear to me |
17:43 | <rbuckton> | I'm still working out a fresh design for ADT enums. I think that if I can work out the performance characteristics of ADT enums with implementations to everyone's satisfaction, there's a huge opportunity for ADT enums to gain significant traction. |
17:44 | <ljharb> | (but certainly i think matchers should avoid being overtly clever. cleverness is an antipattern) |
17:44 | <rbuckton> | And ADT enums are strongly tied to both instance and structure, since instance is the part of the enum domain that I'm hoping will give it the performance characteristics necessary to be worthwhile. |
17:45 | <ljharb> | almost all of my enum use cases would not involve a class |
17:45 | <rbuckton> | if you are talking about number or symbol-valued enums, that's not the focus. |
17:46 | <ljharb> | yes, that's the primary use case for enums imo and ime, and i'm not yet motivated by other ones |
17:46 | <rbuckton> | Yes, they need to be supported, but the benefit of ADT enums is actually how engines can optimize for them vs. regular objects. |
17:46 | <Jack Works> | hm, maybe the criteria for your "smart" isn't clear to me |
17:46 | <ljharb> | something that does what your JSON.parse matcher did seems useful; using JSON.parse for it to me seems overly clever. |
17:47 | <rbuckton> | By having a closed domain of type identities associated with enum values, a specific class of inline cache can be used that avoids megamorphism when branching on the type of an enum value. |
17:47 | <ljharb> | that sounds like a very niche performance need that most practitioners won't care or think about (which doesn't make it unimportant, but does mean it wouldn't achieve much dev traction) |
17:47 | <rbuckton> | i.e., if you take TypeScript's AST for example, every node.kind is megamorphic, while individual branches are ideally monomorphic. |
17:48 | <rbuckton> | that sounds like a very niche performance need that most practitioners won't care or think about (which doesn't make it unimportant, but does mean it wouldn't achieve much dev traction) struct . Fixed object layout is extremely important for engines, and you can't guarantee that with a regular Object. |
17:48 | <ljharb> | structs are also incredibly niche |
17:49 | <ljharb> | the majority of devs won't ever use structs directly or think about them. |
17:49 | <ljharb> | certainly the engine, and things like TS or other libraries, can benefit, which is why it's still worth spending time on it |
17:49 | <rbuckton> | I think the opposite would be true for ADT enums. |
17:49 | <Jack Works> | i.e., if you take TypeScript's AST for example, every |
17:50 | <ljharb> | i would be very surprised if non-primitive enums were ever adopted at scale. (primitive enums, most certainly will be) |
17:50 | <rbuckton> | Structs are niche, but would have an outsized impact on the ecosystem as they're most likely to be used by major applications with broad reach (Google Docs, Office 365, etc.) |
17:50 | <ljharb> | right - i'm not disputing that anything that makes major apps/tools faster has a large impact |
17:50 | <rbuckton> | ADT enums are likely to be used by everyone as a convenient way to model related information. |
17:51 | <ljharb> | but that's a different claim than "developers will use this directly" |
17:51 | <ljharb> | i look forward to an ADT enum presentation that helps me understand why it's a thing anyone should care about - i haven't understood that yet. (i've long believed primitive enums are a thing everyone wants) |
17:52 | <rbuckton> | Developers already use similar mechanisms (i.e., discriminated unions), but they constantly suffer from the performance bottleneck of megamorphic ICs. If ADT enums can avoid that bottleneck, they're very likely to gain adoption. |
17:55 | <rbuckton> | The pushback I usually get on primitive enums is that the same thing can be accomplished via an object literal. My original enum proposal has long had value-adds far above the object literal case, but ADT enums are a whole world unto themselves as far as new capabilities. |
17:55 | <rbuckton> | With an object literal, the engine has to treat every access as a property access, there's no special casing that can go on there. |
17:56 | <ljharb> | right - a net new mental model is something that will be difficult to impart to devs, i think. (also i have zero grasp of it so far) |
17:56 | <rbuckton> | With an enum that has a well-defined, immutable domain, engines can use that type feedback to introduce specific optimizations that aren't otherwise possible. |
17:59 | <Jack Works> | but that's a different claim than "developers will use this directly" |
18:00 | <rbuckton> | For instance
An implementation could use type feedback from |
18:06 | <rbuckton> | You could imagine opt has an internal representation analogous to map { enumType: Option, member: map { enumMember: Option.Some, instance: map { value: ... } } } , such that each when clause starts with a monomorphic IC lookup against map { enumType: Option, member: heap } , and the first branch has another monomorphic IC lookup against map { enumMember: Some, instance: heap } . By the time you get to the nested pattern you're still essentially on a code path that is entirely monomorphic. |
18:07 | <rbuckton> | vs. a flat internal representation of map { constructor: Option.Some, value: ... } that differs from map { constructor: Option.#None } , which are different maps and thus a polymorphic IC. |
18:10 | <rbuckton> | From the JS developers point of view, they just write when Option.Some(let value) or opt.value and it acts like a normal JS object. This is something that implementers strive for with class (and one of the reasons we had to add things like accessor to decorators), but it still isn't entirely reliable for class due to all of the shenanigans that developer's play with regular objects. |
21:14 | <ljharb> | I don't care about the performance though. ADT enum can improve many people shape their program, how they represent data structures in their code. so yes. they'll use this feature directly especially typescript users. |
21:14 | <ljharb> | as much as i actually do like the Option pattern from scala etc, it's not javascripty. |
22:01 | <rbuckton> | Pattern matching isn't javascripty. Nothing is javascripty until its in the language. ADT enums are javascripty though, as they are readily modeled in JS as discriminated unions or even classes, but without the potential performance benefits. |
22:07 | <rbuckton> | If we had them now, I'd model the custom matcher return value using them instead of an iterable.
We already have |
22:41 | <ljharb> | Pattern matching isn't javascripty. Nothing is javascripty until its in the language. ADT enums are javascripty though, as they are readily modeled in JS as discriminated unions or even classes, but without the potential performance benefits. |