01:09
<Evan Winslow>
To be clear, when I said X% I meant "X% of people who would otherwise be using class methods" not "X% of all JS developers". I have a hard time imagining that there is a large contingent of method-chainers that would prefer hack pipes over call-this, but I suppose it's technically possible.
01:42
<Evan Winslow>

the most important feature of Hack pipes is that, like other pipe styles and like call-this, it encourages DCE-friendly API use.

👏👏👏👏

I really strongly believe we need to stay focused on this particular point. It benefits basically all of humanity, and the poorest the most.

01:46
<Evan Winslow>
Can I persuade anyone to update the call-this and pipeline repos to explicitly mention DCE as THE primary motivation, and others as secondary motivations?
02:13
<Evan Winslow>

FWIW, I don't think this is a great argument since all call-this spellings face similar "I got them mixed up" objections. E.g. other delegates have said things like: "I never want a beginner to wonder 'which was it again? . or ~>?'" So I have been going forward with the assumption that some people are going to get mixed up sometimes and the important goal is "easy to detect a mistake" and "easy to fix a mistake" not "hard to make a mistake".

  1. Syntax constraints / autocomplete / linters / TS / asserts / tests all help prevent actual bugs sneaking in;
  2. starting with a . makes it easy to discover both member methods and tree-shakable methods; I never have to wonder where to start since it's the same character either way
  3. if you mistype it, it's the easiest to recover from. One keypress to flip to the other option.
  4. I was hoping using another character familiar to method-chainers . would make the switch feel "simple" or at least "not as scary". To invoke a method, use .; to invoke an extension method, use .. (extend the dot). Easy.
  5. IMO any of ::, .., ~>, etc will be fine to learn for people who find themselves stuck with what we decide. They will just learn it and move on... or the AI will write the code for them and it won't matter anyways. We are never going to come up with something immediately intuitive to everyone...
02:14
<Evan Winslow>
That said, your and Ron's objections are noted and I am happy to compromise on whatever spelling would get through committee. I continue to believe that call-this' main benefit is DCE, not spelling, and the main hindrance is the this bit, not the spelling.
02:51
<Evan Winslow>

Another aspect of this discussion that I think merits consideration, given a goal of persuading method users to switch to something more tree-shakable: precedence. Methods are tight, which means there are several cases where migrating from normal method calls to a "loose" pipeline is... awkward. As a simple example, take any awaited method call:

// Class methods
await this.deletePost(id);

// Call-this / tight-elixir
await this..deletePost(id); // Easy peasy

// Hack
await this |> deletePost(##, id); // Oops!
this |> await deletePost(##, id); // No more bug, but this is pretty different from method chaining at this point...
await (this |> deletePost(##, id)); // No more bug, but oof, we're back to paren-balancing...

Has this issue been discussed yet?

04:38
<Evan Winslow>

Another example is arithmetic between the results of two method calls, based on real example for our codebase:

// Class methods
this.fn1() + this.fn2(arg1, arg2);

// Call-this / tight-elixir
this..fn1() + this..fn2(arg1, arg2);

// Hack
(this |> fn1(##)) + (this |> fn2(##, arg1, arg2));

// Plain functions
fn1(this) + fn2(this, arg1, arg2);
04:40
<Evan Winslow>

Boolean expression, also based on a real example:

// Class methods
if (foo && !bar.isBar()) { ... }

// Call-this / tight-elixir
if (foo && !bar..isBar()) { ... }

// Hack
if (foo && !(bar |> isBar(##))) { ... }

// Plain functions
if (foo && !isBar(bar)) { ... }
10:21
<Ashley Claymore>
re: "going in circles".
10:23
<Ashley Claymore>
this is how I felt with the R&T proposal and created https://acutmore.github.io/record-tuple-laboratory/ to effectively show there is no design that will make everyone happy. The University Of Bergen wrote a paper on this https://dl.acm.org/doi/10.1145/3732771.3742715
19:17
<jschoi>
This is really cool. I really need to keep in touch with Mikhail more—I’m interested in coauthoring academic papers from TC39 too.
20:14
<jschoi>

Evan Winslow:

Can I persuade anyone to update the call-this and pipeline repos to explicitly mention DCE as THE primary motivation, and others as secondary motivations?

I would be glad to take pull requests for both the pipe and call-this proposals. TabAtkins, rbuckton, and I are currently the co-champions of the pipe proposal, and I am the champion of the call-this proposal.
I have also been putting off a rewrite of the pipe README for years because of work. Once I have some personal bandwidth, I will try to prioritize revisions that give this more emphasis over the next few weeks.

20:14
<jschoi>

One caution about emphasizing DCE’s benefits for call-this: if both pipe and call-this are framed primarily around DCE, that increases the chance that some people in TC39 (e.g., browser implementers, Mark Miller) will press us to pick just one of them as the DCE-friendly dataflow feature. And there are also people in TC39 (e.g., ljharb) who would prefer call-this over pipe if it came down to choosing only one.

[from September 2017] @littledan makes a first presentation for F#-or-Elixir pipes to TC39, successfully advancing to Stage 1. However, parts of TC39 object to redundancy with a bind operator. A condition of the advancement to Stage 1 is that it would not be redundant with a bind operator; this will become relevant later.

[from August 2018] ljharb voices concern that advancing pipe would kill any future bind operator (see § 2017-09). Other representatives respond that Hack pipes are now orthogonal to any bind operator and would not kill it. @ljharb decides not to block Stage 2.

I would be unhappy if we ended up with pipe operator but not call-this, but I would be even more unhappy with call-this and no pipe operator. I want to be able to use existing standalone functions: current DCE-friendly modules that do not use this—which is almost all of them—as well as built-ins like Object.entries and Array.from. There are very few APIs, if any, built around standalone this-based methods, aside from Node’s internal primordials, and I am not even sure whether Node still relies on those.

That is one reason I have tried to emphasize call-this use cases that are not really about dataflow. The existing call-this README purposefully spends a lot of time on method wrapping, conditional method switching, method reuse after monkey patching, prototype-pollution protection, and other reasons why people use .call today. Currently, it purposefully does not mention dataflow at all. The idea is to argue that .call is common enough to deserve syntax on its own, regardless of whether it is being used for DCE-friendly dataflow, to avoid it overlapping with the pipe operator. (I have also explored a demethodize function method, equivalent to Function.call.bind, that would make those cases more ergonomic too, but ljharb has said it would not address his own use cases unless it were syntax.)

20:18
<Evan Winslow>

I would be unhappy if we ended up with pipe operator but not call-this, but I would be even more unhappy with call-this and no pipe operator.

You must be as miserable as me right now, having neither ^_^

20:18
<ljharb>
picking just one wouldn’t solve the problem though - because solving DCE requires adoption and just one won’t get full adoption. It’s the combo that overlaps and covers things.
20:20
<Evan Winslow>
IIUC, this would imply that there is a signficant contingent of method-users that would switch to hack pipeline but not to call-this.
20:21
<Evan Winslow>
The main thing that improves DCE, so far as I can tell, is if people choose to use something instead of class methods. Using hack pipes with functions that are already tree-shakable doesn't improve tree-shaking...
20:23
<jschoi>
Yes, insofar that we connect pipe operator to DCE, the argument would be: “We want to encourage people to write and use standalone functions instead of prototype methods a lot more, and people are often not doing this because chaining standalone functions is not ergonomic/fluent enough.”
20:26
<jschoi>
I’m a bit skeptical that call-this would encourage widespread writing/usage of standalone this-using functions nearly as much as a pipe operator would encourage more writing/usage of ordinary functions…but I suppose that it’s even less ergonomic right now to use x.call(f).call(g). than g(f(x)). Or, for your prototype-pollution-protection case, thisBoundG(thisBoundF(x)).
20:27
<jschoi>
In any case, that’s why I did focus call-this on “anything but dataflow”. Focusing both pipe operator and call-this on dataflow would have blocked both from Stage 1 in the first place in July 2017 due to perceived “redundancy”, and I was trying my best to activate those hackles again when presenting call-this.
20:34
<Evan Winslow>
Gotcha, so if you're right about that, then it makes sense why both would help. You just feel there is a substantial contingent of method users (perhaps even a majority?) that still would not switch to defining "extension methods" on which they can use call-this, because this-using standalone functions are just too weird, but they would switch standalone functions using hack pipes since those functions are just normal.
20:35
<jschoi>
Yes. But also, are we really going to ask Firebase and everyone else who has already switched from prototype methods to exporting standalone functions to switch again to this-using functions to make those Reddit users happy with tree-shakeable and fluent syntax? It’d be better to make the already-predominant tree-shakable API pattern, standalone ordinary functions, more ergonomic and fluent.
20:35
<jschoi>
But I do also want call-this. I’m just afraid of triggering the “it’s-redundant” response again. And the redundancy/overlap issue has kept coming back up after 2017. I fear that focusing both pipe operator and call-this on DCE would exacerbate it.
20:44
<Evan Winslow>

I would not ask, because they already decided it was worth making some people mad to get tree-shaking, so they are not the audience for my efforts here. New syntax will not improve their tree-shakability.

Their users might ask I suppose. And if they decided to oblige and provide a call-this-compatible API, that would simply be their prerogative as library maintainers. Same as picking any other style like class methods, first-arg, last-arg, curried...

20:48
<jschoi>
The argument here is that having a fluent style for ordinary functions might make users more likely to choose APIs that use ordinary functions, which would improve tree-shakability; and it might make API authors more likely to choose to write APIs that use ordinary functions, which would also improve tree-shakability. As for Firebase specifically, Firebase’s authors committed to their choice of API style, but prospective Firebase users have not yet. Even current Firebase users may switch away from Firebase if there was an API with better DX (ignoring vendor lock-in effects).
20:55
<Evan Winslow>

The argument here is that having a fluent style for ordinary functions might make users more likely to choose APIs that use ordinary functions

To be clear, I agree with this argument. I just maybe have different intuitions about the magnitude of the effect?

21:08
<Evan Winslow>
I see threads like https://github.com/tc39/proposal-pipeline-operator/issues/238 and reflect on all the class-based code I see at Google and reflect on my own intuitions for what is attractive or not, and try to imagine the migration story of moving a codebase from class methods to hack pipes to improve tree-shaking, and I get pretty nervous about attractiveness of hack pipes to people who like methods, who fully think in classes/methods terms. It would be really helpful if we could somehow quantify the difference. I do not have good ideas here, sadly.
21:35
<Evan Winslow>
Rephrasing my point/question: I don't share this intuition, but would be glad to be wrong. Can you elaborate more? If we can provide evidence that there is a significant portion of method users that would use hack-pipes if it were available, but not call-this if it were available, that is a much stronger reason from a tree-shaking perspective to get both.