| 03:32 | <Justin Ridgewell> | I think Evan is leaning into this specifically because it works well with optional chaining syntax: o?..method() could short circuit if o is nullish. |
| 03:45 | <Evan Winslow> | Whoa never even proposed for stage 3, I didn't realize. |
| 03:52 | <Evan Winslow> | Yes. Also starts with a dot, huge Autocomplete win. People have said "dot chaining just feels so familiar". Easy to type and delete to get back and forth from normal methods which I think mitigates the "which one was it?" concern somewhat. I dunno it's my favorite right now and hasn't gotten much consideration historically so I figure I might as well try it out a bit while we're talking about it. |
| 03:58 | <Evan Winslow> | All spellings have received one complaint or another. I think the main barrier to overcome for that proposal is this-hesitancy, not spelling. I will accept any spelling that can get through committee if we can figure out how to overcome the this-phobia first. |
| 04:19 | <Evan Winslow> | Another bit of feedback that was mentioned during plenary was "will new syntax actually be attractive enough to induce people to switch"? Given that it's a key premise I think it is entirely fair question and I want to do some due diligence to validate that assumption. I'm planning to reach out to a couple of the libraries I mentioned in my talk and get a pulse from their maintainers and engaged community members on call this and hack pipeline. |
| 04:20 | <Evan Winslow> | If anyone has recommendations on a better way to go about this, do share 🙂 |
| 04:48 | <Ashley Claymore> | 'obj..fn()` is most usually complained about in terms of conflicting with the existing semantics for `1..toString()` |
| 04:49 | <Ashley Claymore> | personally I'm fine with the similarity as I dont think it will come up in practice. theres not much benefit to calling a custom method on a number literal |
| 04:58 | <Ashley Claymore> | I think that would be some fantastic community outreach. |
| 05:00 | <Ashley Claymore> | If some of the largest web libraries say they have a preference for pipe style and that they would offer a more tree shakable API if pipeline existed that would be very compelling motivation |
| 05:04 | <Ashley Claymore> | example of the "current" (3yrs ago) push back from consumers when a library (Firebase) moved to functions: https://www.reddit.com/r/Firebase/s/j9rJJa0YsB Things just take longer to program. They are backwards. |
| 06:08 | <ljharb> | structs seem completely orthogonal to me |
| 06:09 | <ljharb> | ..( should never be a viable option for anything imo, it's a bug farm |
| 09:04 | <Ashley Claymore> | |
| 14:35 | <jschoi> | Another bit of feedback that was mentioned during plenary was "will new syntax actually be attractive enough to induce people to switch"? Given that it's a key premise I think it is entirely fair question and I want to do some due diligence to validate that assumption. I'm planning to reach out to a couple of the libraries I mentioned in my talk and get a pulse from their maintainers and engaged community members on call this and hack pipeline. I agree that community outreach here would be useful. The pipe operator README already has a lot of examples of turning deeply nested expressions into linear ones, so that might be helpful for outreach. The big argument is that making an expression a little longer with an explicit Call-this and this-based standalone functions are also a tree-shakeable alternative in a lot of cases, and they preserve that tacit style. But they’re less flexible, since they do not help linearize ordinary functions like Array.from (very common), array or object literals (very common), spread syntax, await, arithmetic, and so on. Still, some API designers and developers may prefer call-this to pipe operator, in worlds where we must choose one between them. I’d be interested to hear what they think. |
| 14:36 | <jschoi> | example of the "current" (3yrs ago) push back from consumers when a library (Firebase) moved to functions: Maybe we should add some Firebase examples to the pipe readme… I do think the “you need to KNOW the names of these functions in order to import them” remark kind of funny. Is that not also true for ordinary methods? |
| 15:00 | <jschoi> | I do know that at least one prominent API designer, Ben Lesh of RxJS, went in that direction too: he redesigned RxJS around standalone ordinary functions. Back then, he was very enthusiastic about F# pipes for tacit functional programming and reacted very negatively to Hack pipes trading tacitness for explicitness. When engine implementers pushed back on F# pipes, he became broadly disillusioned with TC39, with strong language. He has even said he would prefer that nothing be added to the language rather than Hack pipes. Even though I like Ben Lesh’s work, and I like tacit FP, I still do not fully understand why he feels that strongly about needing tacitness, rather than reading linearity. Anyways, you might also encounter his opinions or similar opinions from other people in the community. It would still be good input. |
| 16:05 | <Evan Winslow> | Autocomplete helps with method names a lot. You can get a list of methods without knowing any names at all. Just . and you're on your way. The dot is powerful... |
| 16:10 | <Evan Winslow> | I should also say that "Works with lots of existing expressions and functions" is not a motivation for me, because those are already tree shakable. The impact of our effort here on tree shaking depends specifically on convincing would be method users to do something more tree shakable instead. |
| 16:29 | <jschoi> | Ordinary functions are already tree-shakeable, but they are not ergonomic because ordinary function calls are not linear. They are prefix forms, so they often lead to deeply nested expressions, lots of parenthesis tracking, and a back-and-forth reading pattern. And from what you found, the main complaint about Firebase’s move to ordinary functions for tree-shakeability was that they were harder to read, right? A perceived loss of fluency in reading dataflow expressions—probably due to loss of linearity, and perhaps loss of tacitness. |
| 16:32 | <Evan Winslow> | Ok so we should connect those dots more explicitly: "makes the existing corpus of standalone functions more attractive to method users" or something like that. |
| 16:34 | <jschoi> | Yes, that’s right. The link between the pipe operator and tree-shakeability is that pipes could make tree-shakeable code more appealing by making ordinary-function APIs easier to read and use. The idea is to answer complaints that So the real question is whether gaining linearity, even without tacitness, improves fluency enough that developers would be more willing to adopt tree-shakeable ordinary-function APIs. |
| 16:35 | <jschoi> | …While at the same time also pursuing call-this in parallel, and trying to figure out how much “overlap” the engine implementors (and stewardship-minded folk like Mark Miller) are willing to accommodate. There’s already more than one way to do it in JavaScript… |
| 16:42 | <jschoi> | I’d like to first give call-this another good shot, in the name of “this is a common pattern” and “it might encourage people to write more tree-shakeable code and decrease web dead code”. And also because Jordan is concerned that pipe operator would kill call-this. But, if I had to choose one, I would personally rather live in a world with pipe operator than with call-this. |
| 17:27 | <Evan Winslow> |
I use number-literal extension methods in Kotlin most often for creating durations.
So... I suspect this could definitely become a thing in JS too, although it requires a new helper method. If the autocomplete gets as good as I hope it can, that won't be very much hindrance at all. |
| 17:57 | <Evan Winslow> | So far this pattern does seem to be exceedingly rare in practice. I can only find low-thousands of potential matches on GitHub and many of them appear to be people just figuring out what that even does (e.g. console.log(1..toFixed(0))) or built code rather than source code. Compare to high 10s of millions for this and arrow functions, each. I probably would want my auto-formatter to wrap it in parens or something instead: e.g (1).toFixed() but I just so rarely ever see methods called on number literals in the first place. |
| 18:46 | <Ashley Claymore> |
chaining is great as it avoids deeply nesting. But a number literal can only be at the start. |
| 18:46 | <Evan Winslow> | My assumption is currently that pipeline will be attractive to X% and call-this will be attractive to X+Y%. I would like to get a better feel for the magnitudes of X and Y. X is small + Y is small = do neither. Neither will make a meaningful difference. X is large + Y is small = Just do pipeline. It's more generally applicable and call-this provides only marginal additional benefit to end users. X is small + Y is large = do call-this. Pipeline won't move the needle but call-this will. X is large + Y is large = do call-this, then maybe pipeline if it interests a different set of method-users. |
| 18:48 | <Evan Winslow> | Probably % of users is not quite right either, since not all JS authors affect web traffic equally... I dunno this is hard hahaha |
| 18:48 | <Ashley Claymore> | RxJs is also an example of the exact code engines we're worried about. Every RxJs operator allocates the functor with the bound arguments for the pipe to then pass in the observable |
| 18:51 | <Ashley Claymore> | Pipe can't be proposed for stage 3 (or 2.7). The design is still in draft. |
| 18:52 | <Ashley Claymore> | We need to have a theoretically finished spec with no expected changes sans test/implementation feedback |
| 21:16 | <Justin Ridgewell> | If structs are like classes and define methods, then they're the same |
| 21:17 | <Justin Ridgewell> | Dynamic lookup of methods defeats static DCE, which is what we're hoping to target |
| 21:37 | <Justin Ridgewell> | Note that this approach doesn't solve the "have to know the name to import it" argument. Having a known position (either first arg, or this binding) would. |
| 21:39 | <Justin Ridgewell> | F# also doesn't solve this, because you have to complete the closure call to know what function is being invoked by the pipeline |
| 21:40 | <Justin Ridgewell> | I'd really like to pursue Elixir style (to support known arg position, auto imports, tacitness, and fluency), with PFA layered on (to support any arg position) |
| 22:25 | <Evan Winslow> | Okay thank you for saying so. So far every time I brought up elixir I just get baffled looks so I hadn't been planning on pursuing it further. But I'm open to it if you think it's worth making the case. It certainly a side steps the this-hesitancy issue nicely |