This sounds like the elixir-style pipeline operator (ReScript implements their pipeline operator like this as well). There was a thread on the pipeline proposal discussing this style. Ultimately, they decided to not go that route. See here (which is too bad, I do like this style of pipeline).
Why's that? What's a major advantage to using the fill operator, that the current iteration of the pipeline operator does not provide? When you're needing to pipe, how would you personally choose between these two operators?
These are all of your initial examples, but using the pipeline operator. The end result isn't that different.
It's not the equivalence that matters, it's the syntax
pipe need %, it's not convenient to use
and it's easier to hint (autocompletion) using identifiers instead of expressions
I didn't know about ReScript before, ReScript does have this operator called pipe
but I don't think this operator is a pipe operator
how would you personally choose between these two operators?
Pipe
When the right side is an expression, or not only function calls
Fill
Extension function, Chain call
Of course I want to use dot . , but it's not possible
so I chose ->, which is a pointer in a c-like language, characterized by the ident on the right
The core of the fill operator is the use ident
For autocompletion, especially typescript
using ident can simply search for functions whose first argument is the type of the left expression
But for pipes, how to search expressions, it cannot autocomplete
a->f
Now that ident is used, we can also drop the parentheses directly
This is similar to extension properties in kotlin
oooh, I get what you're trying to go for now. The purpose is to be able to "add" functions to classes you do not control, without actually modifying them. So, if you want a to, say, add a "filter" function to the Map class, you can write this filter function, make sure it's in the local scope, then call yourMap->filter(...). This also explains the weird precedence rules you were going for.
So, conceptually, it's pretty different from ReScript's pipe function, but the way you presented it, it has very similar behaviors.
You might be interested in the bind-this proposal, which is means to resurrect some ideas from the extensions proposal. Its primary purpose isn't to help with this specific use case, but its current iteration can be used for this use-case, and I know at least one delegate is rooting for the bind-this proposal primarily for this purpose. It would let you write code such as this:
const filter = function(filterFn) {
if (!(this instanceof Map)) throw new Error('Receiver must be a Map instance')
return new Map(this.entries().filter(filterFn))
}
new Map(['myKey', 2])
::filter(([key, value]) => value > 1)
.get('myKey')
The languages listed here are all statically typed languages, where extensions can be looked up and dispatched at compile time. This wouldn't be possible in JavaScript without sufficient syntax to make it unambiguous.
TypeScript's auto-complete for JavaScript could prioritise suggesting identifiers on the right-side of a pipe-operator, even if it is an expression position.