17:57 | <TabAtkins> | jschoi: Oh man, this diagram is great. |
18:00 | <TabAtkins> | Hmm, I wonder if Extensions has a way to handle the syntax ambiguity of its trinary form - is x?y::z:f() equal to x ? (y::z:f()) or x ? (y::z) : f() ? Does it depend on whether there's a trailing : elseVal afterwards? |
18:04 | <jschoi> | Hmm, I wonder if Extensions has a way to handle the syntax ambiguity of its trinary form - is |
18:04 | <TabAtkins> | I'm talking at a higher level of parsing, before evaluation occurs. |
18:04 | <jschoi> | Oh wait I see. |
18:04 | <jschoi> | Yeah, I see. |
18:05 | <TabAtkins> | The ?: trinary really poisons single-colon usage. |
18:10 | <Nicolò> | TS and Flow are a nightmare to parse because of their usage of : for return type annotations (especially of arrow functions) |
18:19 | <TabAtkins> | Hrmmm, Extension's obj::foo = 1 syntax for setters doesn't generalize. obj::foo::bar = 1 will call foo as a getter, then bar as a setter, meaning you still can't use it for functional data structures, which need to unfold the earlier parts of the assignment chain into get/set pairs. |
18:23 | <jschoi> | Regarding Regarding CC: HE Shi-Jun |
18:24 | <jschoi> | (By the way, Nicolò: if babel/babel#13973 looks good to you, I’m going to start work on @[] /@{} syntax for tuples/records soon based on that pull request.) |
18:54 | <TabAtkins> | Okay yeah, looking over it freshly and in depth now, I think Extension's only real wins are (a) reusing methods that happen to be generic enough to be useful on arbitrary objects (relatively rare outside of Array), and (b) adding getters/setters to objects without having to screw with the prototype. |
18:55 | <TabAtkins> | The NS polymorphism letting you define a function foo(arg0, arg1) and then call it as arg0::NS:meth(arg1) isn't any better than pipe's arg0 |> NS.meth(##, arg1) , and pipe has less magic going on in that case. |
18:56 | <TabAtkins> | The "add a method to an existing class without screwing with the prototype" use-case is handled just as well by pipe, as above. |
19:02 | <TabAtkins> | And yeah, just confirmed for myself that existing getters/setters don't handle functional data structures well either; x.foo.bar.baz just calls the "foo" and "bar" getters then the "baz" setter and nothing else |
20:04 | <jschoi> | I imagine that whatever “property descriptor” objects that extensions use would actually have to be a new kind of recursive “reference record” object, but Hax might have something else to say about this. |
20:04 | <jschoi> | I wonder if it would be worth carving out January plenary time to present this diagram and discuss all of these proposals at once… |
20:26 | <TabAtkins> | I think it would be, yeah |
20:26 | <TabAtkins> | Wrote up my thoughts after digesting this: https://gist.github.com/tabatkins/60d831d3e304e3e7316d473f5c1f269b |
20:28 | <TabAtkins> | IIRC, ljharb's main desired use-case for bind-this was method extraction - I forget, was it for reliable use on objects of the type it was extracted from (just protecting against prototype mutation) or for calling on different types of objects? |
20:33 | <ljharb> | it's for whatever it takes for me to robustly invoke a function while providing the receiver method extraction + normal invocation achieves this. so too would syntax to call with a receiver. |
20:33 | <jschoi> | My argument for bind-this is that .bind and .call (especially .call) are immensely common in general; .call occurrences in the top-1000-downloaded NPM packages are more frequent than .slice, .set, and .push occurrences combined; .call occurrences exceed even console.log occurrences. I think there are at least four or five different use cases in which .call occurs in, although I suppose they could be lumped together into your second and third use cases. (You say that your second use case is rare, but it actually occurs quite frequently in the NPM dataset, from what I recall, but I’d need to recheck.) |
20:35 | <jschoi> | The sheer frequency of already-extant .call occurrences alone suggests that .call may be worth optimizing for better word order and conciseness. The pipe operator solves .call’s word order but not .call’s conciseness. |
20:38 | <jschoi> | Some more details about found extant use cases for .call can be found starting at https://github.com/tc39/proposal-bind-this/issues/12#issuecomment-939400362. |
20:39 | <jschoi> | …which resulted in the results listed in https://github.com/tc39/proposal-bind-this/blob/main/README.md#bind-and-call-are-very-common. |
20:40 | <jschoi> | To sum up, I think that the second and third use cases that you list for bind-this in the Gist are (perhaps surprisingly) not rare; they are in fact very frequent in existing code, and therefore they may be worth optimizing for. So I disagree with that part of the Gist, although this reasoning is obviously motivated by the fact that I am bind-this’s champion, haha. |
20:41 | <jschoi> | I think the rest of the Gist makes sense; great job in general. |
20:47 | <TabAtkins> | I need to reread your .call() data; it's still the case that I have approximately never seen those methods used in real code, so the extremely heavy usage still blows me away. |
20:48 | <jschoi> | That would be great. The procedure to print all dataset matches in a terminal is hidden in a element, at the bottom of that section in README.md. |
20:51 | <TabAtkins> | Okay, yeah, the "reuse an array method" cases being very common are unsurprising, but generally iterator helpers and/or just using [...x] are just as good. The Object.prototype stuff, similarly - those should all go thru the same transform as Object.hasOwn() , honestly. |
20:53 | <TabAtkins> | Any anything around transpiled code isn't, imo, an important use-case. Transpilers don't need nice syntax for what they're doing, they're outputting write-only code in the first place. |
20:54 | <jschoi> | Yes, definitely agreed on not caring about optimizing for transpilation: we did exclude any transpilation artifacts that we found (they’re excluded by the CLI command and are also listed in a table with explanations in the README.md element.) |