-
Notifications
You must be signed in to change notification settings - Fork 107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replacing ::
completely with pipelines
#110
Comments
Thanks for looking at the smart-pipelines proposal. For what it’s worth, the smart-pipelines proposal already discusses all three forms of the current proposal for the Although Feature PF does subsume, my current opinion is that function application and binding are orthogonal (as I say in #107). Being able to distinguish I’ll examine the rest of this more closely when I can—right now I’m hurrying to finish the explainer and specification as much as I can before the London TC39 meeting tomorrow. Thanks again; I’ll be thinking about this for the next days. Let me know if you read that existing section on |
Oh, I've seen this part but I stopped at “But the other two use cases (infix I'm glad that you've thought about the possible coexistence of Nevertheless I wish you good luck at the TC39 meeting! I'm pretty sure that smart pipelines are the future of JavaScript and you will kick a*! 💪 |
Thanks for the kind words. As the existing In any case, I won’t be presenting to TC39 myself; @littledan will be presenting, though @mAAdhaTTah and I together wrote the presentation slides. We’ll see what happens. Thanks again. |
There are benefits of the unary form (for “method extraction”) that are impossible to achieve with pipelines; namely, caching bound methods off of mutable objects (like builtin prototypes) for later use, while being robust against other code deleting or replacing those methods. I will not be comfortable with the pipeline proposal advancing (and thus potentially killing the :: operator) unless this use case is met by something (in pipelines, or in a separate proposal) that the committee still considers palatable. |
@ljharb: Thanks for the heads up. I would be happy to investigate your use case. I know that TC39 is imminently meeting again, but, when you have time, could you write an example that concretely demonstrates the need to robustly cache bound methods from mutable objects? It’d make it easier for me to explore and/or specify, but I cannot yet find one in the current bind-operator proposal repository, in both its explainer and its issues. Thanks. |
Every place in my packages that i do |
This concerns me a bit, because I don't think the F#-style has a good answer for this use case. The whole raison d'être of that proposal is to be minimal and lean on arrow functions to fill a lot of the gaps that are filled in Smart Pipeline by the lexical topic concept. That said, F#-style isn't really intended to kill Does a method extraction syntax, bind op or otherwise, have to advance in tandem or is leaving the possibility open enough to overcome your objections? |
@mAAdhaTTah note that i don’t think pipelines have to provide for method extraction, i just want to make sure that something - including another proposal - can solve for it. It would be sufficient if some proposal exists, is intended to be advanced, and the committee response is positive. |
@ljharb: That’s also good to know. Robust method extraction also might be orthogonal to Proposal 4 (Smart Pipelines) with Feature PF, similarly to how it is orthogonal with @mAAdhaTTah’s Proposal 1 (F-sharp Style Only with If not, then I would be happy to help out with a proposal for robust method extraction, whether it is with the original binding operator or with another operator. I’ll also search the previous TC39 meetings’ notes for your discussion of robust method extraction. It must have been before last September, or else I would have already seen it… @mAAdhaTTah: It’s short notice, but we might want to update the presentation in anticipation of this discussion about our proposals’ relationships with method extraction and to address @ljharb’s concerns. I don’t yet know how though. We might have to quickly look at @ljharb’s packages and the prior TC39 meeting notes, later today, then figure out where to go from there… |
@js-choi Let's not, imo; some of the slides are already pretty jam-packed, with a lot for the committee to digest. Both proposals leave open the possibility of method extraction; let's see what direction we get (if any) from the committee at this meeting and proceed from there. |
I agree that this presentation doesn’t need to address it; pipeline isn’t seeking advancement this go-round. |
@mAAdhaTTah, @ljharb : Understood. I had forgotten that a discussion about robust method pre-extraction happened last September. By the time they returned to it in November, time was up. January was skipped while preparing for this, though @ljharb gave a comment about the importance of the prefix In any case, pipelines, including smart pipelines, and robust cached method pre-extraction can coexist. Using return fn
|> &Function.prototype.toString
|> &String.prototype.match(#, classRegex)
|> !!#; …which is just: return !!&String.prototype.match(
&Function.prototype.toString(fn),
classRegex); This security robustness is quite a different use case than simply wanting to express the callbacks in I think secure cached method binding is out of scope for smart pipelines, even with Feature PF. It is also out of scope for @mAAdhaTTah’s Proposal-1 pipelines. These are orthogonal use cases. They cannot kill each other. I will have to look into adding examples that use both pipelines and secure method extraction to the smart-pipelines explainer… |
@ljharb: I’ve pushed a commit to the smart-pipelines explainer that clarifies how it does not address or preclude an operator for robust method extraction. You can see some hypothetical examples in its section about the |
It does somewhat :-) I’ll also be interested to hear the committee’s opinion on a proposal for method extraction. |
I find that the order of operations useful. For example, lets say you have this sample library https://gist.github.com/babakness/ba3c2ac03b030cecceca8a64877a79f4 export class Placeholder {}
export const _ = new Placeholder()
export const isPlaceholder = placeholder => placeholder instanceof Placeholder
export function bind( ...placeholders ) {
return ( ...fillers ) => this.call( this, ...placeholders.map(
item => isPlaceholder( item ) ? fillers.shift() : item
) )
} Then you can do import { _ , bind } from 'cool-stuff'
const getPointOnLine = (slope,offset,x) => slope * x + offset
const pointOnLine = document.querySelector('#whatever').value
|> Number
|> getPointOnLine::bind( .5, 10, _ ) The fact that import { _ , bind } from 'different-cool-stuff'
const getPointOnLine = (slope,offset,x) => slope * x + offset
const pointOnLine = document.querySelector('#whatever').value
|> Number
|> ( getPointOnLine |> bind( .5, 10, _ ) ) But it is less intuitive. |
One advantage I see with the bind operator is that there is no illusion of what is actually being done -- you're calling the RHS function with the LHS set as It appears that progress with this proposal appears to be moving faster than bind operator proposal -- can someone explain why the community favors pipelines? (I know it's likely that this discussion has already happened, but I can't find it, so thanks in advance.) |
The bind proposal and pipeline proposal are generally desired by two different sub-communities - the pipeline operator is desired primarily by functional-programming advocates, and the bind operator is desired primarily by class-based-programming advocates. I'm not sure what role that played in this proposal attracting so much attention. |
I'll also add that the bind operator had momentum before it stalled out. The initial idea of the bind operator covered a lot of different usages, and it stalled out on speccing some of those behaviors. |
function makeExtension(fn) {
return function argumentReciever() {
const arg = arguments
return function thisReciever(self) {
return fn.apply(self, arg)
}
}
}
var say = makeExtension(function (word) {
console.log (this.name + ': ' + word)
return this
})
;({name: "jack"}) |> say('Hello World') I though, some of the usages may be simply described with a helper function to achieve the style of extension methods. And this style would be nice to experiment new stage 1/2 methods as it can be used safely without pollute the prototype chain. It could benefit future proposals by allow you to test brand new methods in production to see if it is really helpful or not without worry about it would breaks everything someday, or simulate virtual methods on native object. However, the resolve order of pipeline operator and bind operator is reversed. ;({name: "jack"})
|> say('Hello World')
.toString() because it world be parsed as ;({name: "jack"})
|> (say('Hello World')
.toString()) |
Closing this issue, as the proposal has advanced to stage 2 with Hack-style syntax. This means it replaces some of the use-cases for |
I'm writing this issue in reaction to #107 and tc39/proposal-bind-operator#44 where there is a vivid discussion about the future of the
::
operator and its relation to the proposed pipeline operators.Let me start with saying that the
::
operator proposal has been around for quite a long time and there have been some major advancements in the Pipeline Operator Proposal since then. For example the Smart Pipelines variant with Additional Feature PF is much cleaner and more universal than the unary binding variant of the::
operator can ever hope to get. I think that the ease with which+> console.log
replaces::console.log
while offering much more functionality implies that the design of::
needs heavy rethinking.Now let me dissect the three variants of
::
, one at a time:Unary Bind operator
::obj.fn
Meaning:
obj.fn.bind(obj)
Use case:
addEventListener('click', ::console.log)
Problem: People don't like the syntax – it's completely different from
::
operators in other languages and if feels a bit weird that::a.b.c
means the same asa.b::a.b.c
.Problem: It produces a new function every time. This wouldn't work in the original proposal:
removeEventListener('click', ::console.log)
However the problem can be fixed quite simply using WeakMap internally to return the same bound function every time.Status: The more universal Pipeline Functions proposal makes it quite redundant. Furthermore it solves the syntax problem –
+>
isn't clear at first sight, but after looking it up, the developers should recognize it as a “crossbreed of the pipeline operator|>
and an arrow function=>
”. The problem with returning a new function every time is however more complicated to solve with PF than with::
. We could therefore leave(+> foo.bar) === (+> foo.bar)
as undefined behavior until we find a systematic way to enforce equality..
Context Pipeline operator
context::fn(...args)
Meaning:
fn.apply(context, args)
Use case:
arr::unique()::sort()::join(', ')
Problem: The only major problem with this feature is that, despite it's quite uncontroversial and requested often by various people, it's being delayed by the rest of the proposal. See Drop the
this
binding altogether proposal-bind-operator#44 for more discussion.Status: Right now, this feature isn't covered anywhere in the pipeline proposal, yet it's quite similar to the pipelines. There have been opinions that, because of the similarity with pipelines and the controversy of the other two variants of
::
, we should change it to something more consistent with the pipeline operator. User @fatcerberus proposed->
instead of it, I would peronally go with.>
or:>
.Differences from
|>
: There is some overlap between the Context Pipeline and the ordinary Pipeline Operator in terms of the extension method functionality. If you wanted to use|>
, you could pretty much use the first parameter instead ofthis
and rewrite the use case of this topic toarr |> unique |> sort |> join(#, ', ')
. You can see that the syntax looks lighter than with::
. However it doesn't feel exactly JavaScript-y, we're all used tothis
being in the spotlight, especially with native types likestring
orarray
. And the#
injoin(#, ', ')
is just weird.My proposal: I don't know if these arguments are enough to add the Context Pipeline to JavaScript despite the ordinary Pipeline can do much of its tricks. However I'd add the operator to the Smart Pipeline Proposal and let the community (and TC39) express their opinion. This would specifically mean removing Context Pipeline from the Bind Operator Proposal and replacing it with Additional Feature CP (i. e. Context Pipelines) for Smart Pipelines. This additional feature would introduce a new infix operator, for example
:>
, where these rules would apply:expression_a :> expression_b
translates to(expression_b).call(expression_a)
expression_a :> expression_b( ...argument_list )
translates to(expression_b).apply(expression_a, argument_list)
If I rewrote the use case again using this new syntax, it would be:
arr :> unique :> sort :> join(', ')
, which is even cleaner than with the ordinary pipeline..
Binary Bind operator
context::fn
:Meaning:
fn.bind(context)
Use case: Eh, binding functions to context I guess?
Status: If Additional Feature PF and NP were accepted together with my proposed CP, Binary Bind operator could be replaced by
+>( context :> fn(...) )
. And with BP it could be written as+>{ context :> fn(...) }
which is maybe even cleaner..
TL;DR
To sum up, we saw that the Smart Pipelines together with a light-weight pipeline-friendly Additional Feature CP would easily replace the whole Bind Operator Proposal. However there are some open questions, such as the implementation of
removeEventListener('click', +> console.log)
or even whether CP is worth introducing a new operator.The text was updated successfully, but these errors were encountered: