tc39 / proposal-bind-operator

This-Binding Syntax for ECMAScript
1.75k stars 30 forks source link

Why is this still stage 0? #35

Closed calebmer closed 8 years ago

calebmer commented 8 years ago

I saw this proposal a while ago and almost every other week I find another situation where I’d want to use it. So why is it still stage 0?

As a note it seems like this proposal is important considering the new iterable additions to the language:

Array.from(iterable::map(x => x)::filter(x => x))

This way we could have lazy map/reduce evaluations.

zenparsing commented 8 years ago

@calebmer For sure. Contact your favorite TC39 member and tell them to get on board with it! 😄

(I'm not currently doing TC39 work, so it can't be me.)

calebmer commented 8 years ago

Unfortunately I haven’t been collecting my TC39 “baseball cards” if you will. Any recommendations? I could just ping every single TC39 member who’s name I recognize, but by the fact that I know there name means they might not be able to pick this up :wink:

calebmer commented 8 years ago

Also, what’s the correct terminology, am I looking for a “champion”?

zenparsing commented 8 years ago

Right, "champion". You might be able to catch Pokemon, I mean TC39 members, by looking at participants listed in the meeting notes. My experience has been that several committee members are positive to the proposal, but none have stepped forward.

calebmer commented 8 years ago

You have obviously worked with some of them before, do you have a name to suggest? :blush:

zenparsing commented 8 years ago

@littledan @domenic @bterlson @jeffmo

I keep getting pinged about why this proposal (bind-this double colon) is still at stage 0. Anyone from your organizations interested in taking it on?

peet commented 8 years ago

I took it that @ljharb was interested (or maybe just supportive in general), from his reaction to his mention on a comment in #24.

zloirock commented 8 years ago

Funny. So that mean all your other ES proposals like 'Observable', private fields or async iteration no longer official ES proposals (champions required for that)?

zenparsing commented 8 years ago

@zloirock Oh, they're still official proposals, for sure, but they need a champion to advance. Async iteration still needs a champion I think, but the other two are covered.

ljharb commented 8 years ago

@calebmer what "new iterable additions"? I've seen no proposal for that.

When my current plate of proposals gets a bit smaller, if this proposal is still unchampioned, I'll definitely try to scoop it up. At the moment, however, I don't have the resources.

calebmer commented 8 years ago

@ljharb I meant something more like “new addition of iterables,” I think that the very existence of iterables and other abstract interfaces like thenables in the specification warrants a feature like this in the language to aid in consuming these interfaces across code boundaries.

@ljharb if you don’t currently have the resources, could you recommend someone who might?

littledan commented 8 years ago

There are a couple different separable parts of this proposal: Infix :: for pipelining and prefix :: for function bind. I've heard that the latter is more useful. Even though I have a huge amount of sympathy for the first one, some people find it confusing because what follows the :: is looked up in the local lexical scope. I've met programmers who say the two things they use non-ES6 Babel features for are async/await (which is almost at Stage 4) and prefix ::.

If someone separated out the two meanings, and confirmed my intuition about the prefix case being the important one, then I think this would be a better proposal. Maybe this work could be done by someone from the community, and following that, a TC39 member could pick it up and champion it more easily (as TC39 members have done for other proposals). The hard part of the work is understanding and communicating the community needs.

I've heard part of the interest in this proposal is that it's thought that prefix :: would somehow be faster than Function.prototype.bind; for V8's part, we've been optimizing that function, so it might be better to leave performance out of this motivation.

The other thing to evaluate is if this is really want we want to use the :: token for (as opposed to, say, types). Once we use it for bind/pipelining, it'd be harder to also use it for something else. We don't have that many nice-looking tokens left in JS, so this is a big deal.

deontologician commented 8 years ago

Personally, I'm interested in this proposal for the infix notation (for use with rxjs and underscore style toolbox libraries). The prefix notation is kinda convenient, but rare enough use case that function.bind is fine

domenic commented 8 years ago

I tend to agree. I always thought the infix notation was the more interesting part, as evidenced by the plethora of es-discuss threads and proposals for different types of pipelining syntax. Prefix only feels like a nice potential bonus, but I'd rather just stick with Function.prototype.bind, if there's no infix version for it to be symmetrical with.

ssube commented 8 years ago

While the bind shorthand is nice in event-heavy apps, I think the pipeline operator is far more useful in a lot more libraries.

bergus commented 8 years ago

I believe both parts are equally important. But is this double-feature really what is holding this proposal from advancing?

bterlson commented 8 years ago

FWIW, this proposal is interesting to me for the infix notation. The prefix is a convenient sugar but not one I think is super critical.

The thing that has been giving me pause about championing this feature is I believe we probably don't want two syntaxes for pipelining things (one via this, ala this proposal) and another via first argument (eg. pipeline operator proposal) and I'm not sure how to combine them or which is more important/a better fit for JS long-term.

Alxandr commented 8 years ago

I agree on the infix operator. Though, the reason it's important to me is the lack of a "better" way to do pipe-lining functions in JS (without prototype modifications). I'd much prefer something that sets first/last argument than the magical this, but this functionality in babel was the only thing that enabled me to write code the way I wanted to, which is why I'm for it. I (as well as others have) also made a library for dealing with all sorts of iterables using this syntax which allows for stuff like [1,2,3]::map(n => n * 2)::toArray(). Though my ultimate wish would be something more F# like:

[1, 2, 3]
|> Iter.map(n => n * 2)
|> Iter.toArray()

To me the :: operator is one of "I'll take it if I can get it", because it's much better than nothing.

bergus commented 8 years ago

@bterlson

we probably don't want two syntaxes for pipelining things (one via this, ala this proposal) and another via first argument (eg. pipeline operator proposal) and I'm not sure […] which is more important/a better fit for JS long-term.

Well you'd have to decide whether you want JS to be more object-oriented or more functional :-) There's been some discussion of this in mindeavor/es-pipeline-operator/issues/2, zenparsing/es-function-bind/issues/26 and zenparsing/es-function-bind/issues/19

I do however proclaim that first-argument-receivers are not functional at all. In properly curried languages, the data comes last, so that partially applying functions is easy and they cannot only be applied or pipelined, but also passed around. So if you want to go functional, you should aim for that.

Passing data as zeroth-argument (this) in contrast is just natural in OOP, and will allow for much simpler method borrowing.

benjamingr commented 8 years ago

I think there is consensus that infix :: is the more interesting one as it allows scoped binding of methods to objects.

bergus commented 8 years ago

To appease the FP fraction, we could even devise a postfix :: operator that desugars

["abc"].some(String.prototype.includes::("b"))

to

["abc"].some(x => String.prototype.includes.call(x, "b")) // or
["abc"].some(((m, ...args) => x => m.call(x, ...args))(String.prototype.includes, "b")) // more precisely

thereby allowing OOP partial application :-) Uh, I'm bikeshedding again, definitely not suggesting to include that in the current proposal.

Mouvedia commented 8 years ago

I suppose the fact that your proposed :: operator conflicts with E4X and JScript doesn't help either.

bterlson commented 8 years ago

@Mauvedia, I don't think it hurts :-P JScript will not be getting support for any new syntax, and it's so old by this point much code you run on the web every day doesn't work anyway.

robotlolita commented 8 years ago

Because JS is not Haskell (or OCaml, or ...), a pipeline operator that does not use the this argument to pass the data would be only really useful if the syntax described where the value should be passed, so:

a |> f(_, b) |> g(c, _)

Would be:

g(c, f(a, b))

Of course, _ can't be used to denote the hole in the application there, and I don't know any other available symbol that works reasonably well for this.

Which is why I'm more in favour of the this::fn operator than a value |> fn proposal.

calebmer commented 8 years ago

@zenparsing, @littledan, @domenic, @bterlson, @jeffmo, @ljharb:

So that we have an actionable next step to getting the proposal a champion—I’ll separate out the infix part of this proposal with the prefix so we effectively have two proposals. Then we would need two champions. Can we agree this is the correct course of action and does anyone want to champion either of these proposals?

@littledan, you expressed interest in the prefix case, would you be willing to champion this half of the proposal?

@domenic, would you be interested in championing the infix half of this proposal?

domenic commented 8 years ago

Sorry, I don't have enough capacity to champion a proposal like this right now.

littledan commented 8 years ago

I'm also not going to champion either of these proposals right now, sorry. There is a separate proposal for |> at https://github.com/mindeavor/es-pipeline-operator/ . @appsforartists mentioned to me that RxJS users make heavy use of this feature; @jhusain, would you be interested in looking into this further?

calebmer commented 8 years ago

@jeffmo, @bterlson, @jhusain:

Do any of you have interest in championing this proposal or part of it? For a quick thread recap, this proposal allows two main things:

This bind prefix syntax:

emitter.on('event', ::this.handleEvent)

…which is equivalent to:

emitter.on('event', this.handleEvent.bind(this))

…and an infix syntax:

observable::map(() => {})

…which is equivalent to:

map.call(observable, () => {})

It seems like there is a lot of demand from the community for both of these features, and we’re looking for a champion for both “halves.” We could keep them in one proposal and have one champion, or we could split them out and have a champion for each.

@jhusain as I understand it the infix syntax is critical for the future of RxJS and ES7+, would you be interested or do you know anyone else who would be interested to champion this proposal?

jhusain commented 8 years ago

I don't think that this proposal is critical to Rx anymore than it is critical to the libraries like underscore or lodash. That said, it would certainly make FP patterns in JS a lot more ergonomic. My concern is the time commitment required to move an additional proposal through the committee. My recollection was that the latter half of this proposal was pretty controversial.

jeffmo commented 8 years ago

Yea, unfortunately the effort to move another proposal from start to finish at TC39 is just far more than I can afford to spend right now.

I do think this is an interesting proposal, though, and would love to see it ship in some form (even if only paired down to one of its two parts).

calebmer commented 8 years ago

@jhusain agreed, but RxJS has taken it one step further by putting it in the docs and calling it the "best method possible." At this moment (without support) this proposal likely won't even move out of stage 0 for another 3–4 months and getting it into the standard could take a whole year. Considering I first heard the excitement for this more than 6 months ago it's a shame that it will take about 2 years for what many libraries consider to be a best practice to become a specced reality.

So considering Rx has a publiclly stated interest in the success of this proposal, could you make the time (or find someone who could make the time) to at least move this proposal forward? And if there's anything the community could do to make time less an issue, what would that be?

appsforartists commented 8 years ago

It sounds like the controversy is around the conflation of method binding (::console.log) and pipelining functions (observable::map()::filter()). Perhaps unbundling those concerns will help move the process forward.

There's a proposal for an independent pipeline operator (|>), but the person who wrote it doesn't have spec text, and may not be familiar enough with the TC39 process to write it on his own. Any TC39 members willing to help mentor @mindeavor through writing spec text?

Igorbek commented 8 years ago

I'm wondering how that pipeline operator could ever be considered as an alternative to bind operator? It solves very different problem. The pipeline operator doesn't offer anything in this binding at all.

zenparsing commented 8 years ago

@appsforartists We went through all of these concerns over a year ago. They are well-documented in the issues. We considered separating the proposals with different syntax, using first-arg, everything, and it turns out that none of those changes really amount to any real identifiable improvements to the feature (beyond OOP-vs-FP bikeshedding and cheerleading).

Of course, anyone that would like to go through the whole process again is more than welcome!

Igorbek commented 8 years ago

@calebmer, I absolutely agree that it is very important for RxJS and other "pipelining" libraries. What we have now in RxJS with having to augment prototype is just a work around. I personally had worked a lot with RxJS typings and prototype approach prevented from better abstractions as we had in Rx.NET. (just a note)

bergus commented 8 years ago

@appsforartists Don't forget that even the inline :: is still just a bind operator, although it can be used for pipelining: observable::map()::filter() desugars to filter.bind(map.bind(observable)())()

appsforartists commented 8 years ago

@bergus I know that. 😄

I've heard from a few sources that the conflation of the two use cases may have been causing friction, so I was just trying to unblock. Sounds like I'm out of my depth/not being helpful, so I'll retreat until I have anything more helpful to add.

zenparsing commented 8 years ago

@appsforartists Apologies if I implied that you weren't being helpful, any ideas to unblock are worth exploring!

ljharb commented 8 years ago

@bergus when followed by () it actually would desugar to .call, not .bind.

domenic commented 8 years ago

It could "desugar" to either. Neither desugaring is literally how it would work; either are appropriate approximations.

Igorbek commented 8 years ago

Ok, so we haven't had any champion still? No more candidates?

bterlson commented 8 years ago

@mattpodwysocki and I will champion this proposal.

calebmer commented 8 years ago

@bterlson awesome 🎉

I'll close this issue now 🙌

caub commented 7 years ago
Array.from(iterable::map(x => x)::filter(x => x))
Array.from(iterable, x => x /*optional map arg*/).filter(x => x)

I don't see how the bind operator would make it better here

edit: oh right, processing less items in Array.from, or also plugging map to iterables

MeirionHughes commented 7 years ago

@calebmer to have generic filter methods usable on other sources of data. i.e.

function* source(){ yield 1; yield 2; yield 3; }
function* filter(predicate){ 
  for(let item of this) 
    if (predicate(item)
      yield item;
}
for (let item of source()::filter(x => x > 1)){
  console.log(item);
}

This is really the huge selling point of the bind operator, because currently its painful to chain separate generators that work off other iterables. Really missing out on some awesome code without this bind operator, imho.

In your example, you're creating an array twice before you get to iterate the result, whereas with generators you map and filter each item one at a time. You can of course roll your own library (like linq ) to help with chaining stuff on iterables... or adulterate the prototypes of things.