00:06
<TabAtkins>
No, if you use the plain ? each is taken as a separate argument; you have to use the indexed variant to reuse placeholder args.
00:06
<TabAtkins>
Since multiple placeholders is a more common case than reusing a single placeholder.
20:47
<sarahghp>
Since multiple placeholders is a more common case than reusing a single placeholder.
So then you're undoing and redoing the meaningfulness of order in the same process ... interesting
20:48
<TabAtkins>
I'm not sure what you mean - the placeholders are still subbed in order
20:48
<sarahghp>
But the whole point of PFA is order is meaningless. Otherwise, you can just use .bind
20:52
<Ashley Claymore>
One issue with .bind is there isn't a way to leave gaps
20:54
<sarahghp>
Which is reordering, right? Leaving gaps means changing the argument order.
20:54
<Ashley Claymore>
  • having sudden flash backs to my c++ days std::bind(f, _1, 42, _2)
20:56
<Ashley Claymore>
I guess when only binding certain arguments it does change order in one way, in that it brings some arguments forwards. But not changing their relative order.
20:57
<Ashley Claymore>
If I've understood you 🙂
21:00
<sarahghp>
Yes, I think you have. It seems like the cost of adding more syntax (in inscrutability) just to get reordering, which can also happen with arrow functions, is a worrisome trade-off.
21:01
<sarahghp>
Especially since it feels like breaking some fairly fundamental agreement, although maybe just to me. 😆
21:27
<TabAtkins>
sarahghp: I'm still not sure what you're talking about, unfortunately. .bind() lets you provide arguments in sequence only; PFA relaxes that and lets you skip args, but still defaults to supplying them in order.
21:29
<TabAtkins>
Omitting arguments from the end doesn't seem (imo, at least) to be significantly different from omitting arguments from the start or center.
21:31
<TabAtkins>
Like, if fn~(a, ?) is "undoing the meaningfulness of order", I don't see how fn.bind(null, a) isn't equally so.
21:37
<sarahghp>
sarahghp: I'm still not sure what you're talking about, unfortunately. .bind() lets you provide arguments in sequence only; PFA relaxes that and lets you skip args, but still defaults to supplying them in order.

Oh no maybe I am being this goat! https://twitter.com/Maschlea5/status/1481014660736462850

But yes, I am saying to me, the salient difference between PFA and .bind is that PFA lets you supply arguments in a different order. In the example of one argument, it doesn't matter. But in the case of x = fn~(arg0, ?, arg2, ?), the code is saying that it is desirable to create functions where arguments can be passed in a different order — so desirable that we've made a shorthand for it —, except then order matters again when the hole-y function x is called. And in that way it's relying on contradictory assumptions at the same time.

It's possible this bothers me aesthetically and doesn't actually matter ... I am still thinking about that but it definitely concerns me now.

21:38
<sarahghp>
It also definitely feels like a lint trap where the rule to always use ordinals comes right after the facility exists. Maybe that's ok too.
21:40
<TabAtkins>
I still don't understand why you're saying "a different order". fn~(arg0, ?, arg2, ?) still takes args in the listed order - (x, y) => fn(arg0, x, arg2, y)
21:40
<TabAtkins>
Are you meaning, like, mentally we're rewriting the arg order to be 0, 2, 1, 3, and then binding the first two ahead of time?
21:43
<sarahghp>
Yes, precisely that.
21:44
<TabAtkins>
Ah. I'm certainly not doing any such transformation. ^_^
21:44
<TabAtkins>
No more than I am when writing the same thing as an arrow func.
21:47
<sarahghp>

But you are are doing that transformation, right? That's literally what's happening. Are you saying you don't think of it that way?

You are right tho, it's not more than an arrow func, except that by making a shorthand syntax for it, we are communicating its desirabltility. And that is where I fall off the train. If you have to reorder something, you can, but it has a tiny bit of friction, which is good, because it's weird.

21:50
<sarahghp>
And by "weird" I mean it deviates from a fairly core understanding in JS, which is that argument order is meaningful. And when it's not, you can communicate that by having an object argument.
21:50
<TabAtkins>
I absolutely don't think of it that way, right. There is zero argument rearranging going on in my head when I write (x,y)=>fn(0, x, 2, y)
21:50
<TabAtkins>
I can't speak for others, since I haven't done more than a smattering of programming teaching, and I know people's mental models can diverge significantly and in surprising ways.
21:53
<TabAtkins>
To put another way, fn~(0, ?, 2, y) and fn~(0, 1, ?, ?) are equivalent in my mental model, but appear to be meaningfully distinct in yours?
21:54
<TabAtkins>
Or more simply, fn~(?, 1) vs fn~(0, ?)
21:59
<sarahghp>
Yes, that's correct.
22:05
<jschoi>
For what it’s worth, the “this is already solved by arrow functions” argument was maybe the biggest reason why PFA syntax didn’t successfully advance to Stage 2 last October: https://github.com/tc39/notes/blob/master/meetings/2021-10/oct-25.md#partial-function-application-for-stage-2
22:12
<TabAtkins>
Yeah, arrow functions do already achieve 80% of what PFA is trying to do, and in a reasonably terse and readable way (slightly longer than PFA, but not terribly so). I've come around to idea that the remaining 20% (pre-computing receivers and arguments, and making "pass a method as a callback" as terse as possible) are worth syntax, but that's very much an arguable point.
22:16
<jschoi>
The other 20%, is it eager function and argument evaluation?
22:17
<jschoi>
I.e., the lazy (x, y) => f()(x, y, a(), b()) versus the eager f()~(?, ?, a(), b()).
22:23
<TabAtkins>
Yeah that and the arr.map(obj.meth) use-case
22:23
<TabAtkins>
which today is usually broken for two reasons
22:35
<sarahghp>
So right now for arr.map(obj.meth) you need arr.map((el) => obj.meth(el)) to limit to one argument. Why else is it broken?
22:35
<sarahghp>
Or verbose, say, since it's possible.
23:01
<TabAtkins>
Yeah, that's just it. You need to do that to (a) limit it to one argument, as likely intended, and (b) keep the obj receiver around. Both are broken by arr.map(obj.meth), but fixed by arr.map(obj.meth~())
23:20
<jschoi>
I think Sarah’s point is that those two problems with arr.map(obj.meth) are also solved by the arrow function arr.map(el => obj.meth(el)), albeit with lazy evaluation and longer length compared to arr.map(obj.meth~(?)).