bind operator (was: arrow function syntax simplified)

# David Herman (13 years ago)

On Mar 27, 2012, at 9:14 PM, Russell Leggett wrote:

I'm sure this is a bit of a tangent, but the other major related case is passing a "method" as an argument but needing to retain the correct "this". Obviously, that is what bind was meant for, but that is inconvenient when passing methods for the same reason it would be inconvenient for anonymous functions.

What if we had a shorthand for bind that worked in both of these cases...

I have a strawman on this topic:

http://wiki.ecmascript.org/doku.php?id=strawman:bind_operator

I agree it's a real need. Just like ... will provide convenient, high-fidelity (e.g., insensitive to Function.prototype monkey-patching) syntax for .apply, we should also have an operator that provides convenient, high-fidelity syntax for .call and .bind. I believe a single operator can provide both.

# Russell Leggett (13 years ago)

On Wed, Mar 28, 2012 at 1:37 PM, David Herman <dherman at mozilla.com> wrote:

On Mar 27, 2012, at 9:14 PM, Russell Leggett wrote:

I'm sure this is a bit of a tangent, but the other major related case is passing a "method" as an argument but needing to retain the correct "this". Obviously, that is what bind was meant for, but that is inconvenient when passing methods for the same reason it would be inconvenient for anonymous functions.

What if we had a shorthand for bind that worked in both of these cases...

I have a strawman on this topic:

strawman:bind_operator

I agree it's a real need. Just like ... will provide convenient, high-fidelity (e.g., insensitive to Function.prototype monkey-patching) syntax for .apply, we should also have an operator that provides convenient, high-fidelity syntax for .call and .bind. I believe a single operator can provide both.

Ah, there you go. I figured I wasn't the first to think of it. I think it might be worth talking about this in relation to the shorthand function syntax, because it could pull the lexical this issue out of that debate. Then we could reduce the arrows to something simpler: -> for blocks, => for

expressions with implicit return. It would also solve the related issue of this binding when passing methods as callbacks, which is also a major issue in a lot of apis, requiring extra parameters for the "this".

# John Tamplin (13 years ago)

On Wed, Mar 28, 2012 at 2:02 PM, Russell Leggett <russell.leggett at gmail.com>wrote:

Ah, there you go. I figured I wasn't the first to think of it. I think it might be worth talking about this in relation to the shorthand function syntax, because it could pull the lexical this issue out of that debate. Then we could reduce the arrows to something simpler: -> for blocks, => for expressions with implicit return. It would also solve the related issue of this binding when passing methods as callbacks, which is also a major issue in a lot of apis, requiring extra parameters for the "this".

To me, the biggest problem when you need bound this is that you have to keep around the bound version so you can remove it. For example:

elem.addEventListener('click', onClick.bind(this)); ... elem.removeEventListener(type, ???);

I can't remove the bound listener unless I saved a reference to it, since another bind with the same callback and object reference gets a new bound function. This adds a lot of extra work, and makes it easy to leak memory.

If the function already had a bound this by the way it was defined, I don't need to keep an extra reference around (this assumes some class syntax that allows the same function shorthands:

class Foo { register(elem) { elem.addEventListener('click', onClick); }

unregister(elem) { elem.removeEventListener('click', onClick); }

onClick(e) => do { ... } }

# Kevin Smith (13 years ago)

I'm not sure how to quantify this, but I believe that if such a bind operator were available, it would be overwhelmingly be used to simulate lexical |this|.

If syntax is about optimizing the common case, then shouldn't we just provide a function form which lexically binds |this|?

# Russell Leggett (13 years ago)

On Wed, Mar 28, 2012 at 2:38 PM, John Tamplin <jat at google.com> wrote:

On Wed, Mar 28, 2012 at 2:02 PM, Russell Leggett < russell.leggett at gmail.com> wrote:

Ah, there you go. I figured I wasn't the first to think of it. I think it might be worth talking about this in relation to the shorthand function syntax, because it could pull the lexical this issue out of that debate. Then we could reduce the arrows to something simpler: -> for blocks, => for expressions with implicit return. It would also solve the related issue of this binding when passing methods as callbacks, which is also a major issue in a lot of apis, requiring extra parameters for the "this".

To me, the biggest problem when you need bound this is that you have to keep around the bound version so you can remove it. For example:

elem.addEventListener('click', onClick.bind(this)); ... elem.removeEventListener(type, ???);

I can't remove the bound listener unless I saved a reference to it, since another bind with the same callback and object reference gets a new bound function. This adds a lot of extra work, and makes it easy to leak memory.

If the function already had a bound this by the way it was defined, I don't need to keep an extra reference around (this assumes some class syntax that allows the same function shorthands:

class Foo { register(elem) { elem.addEventListener('click', onClick); }

unregister(elem) { elem.removeEventListener('click', onClick); }

onClick(e) => do { ... } }

I think that's a very specific use case. Not that its uncommon, its just that bound this is quite common in my experience without needing to hold the reference. One possibility for your case, though, would be if the bind operator always returned the same function. That would make it different than the way the bind function works, but it has a certain amount of sense. If this.onClick always refers to the same function, why not ::this.onClick? Of course I know that gets a little tricky. What is it returning after all? Do we create some concept of a method pointer? Something like C# delegates? C# delegates can wrap a static function or instance method and can use == to compare equality.

(Regarding the strawman syntax, I imagine the :: is going to have conflict with guards, no?)

# Russell Leggett (13 years ago)

On Wed, Mar 28, 2012 at 3:17 PM, Kevin Smith <khs4473 at gmail.com> wrote:

I'm not sure how to quantify this, but I believe that if such a bind operator were available, it would be overwhelmingly be used to simulate lexical |this|.

If syntax is about optimizing the common case, then shouldn't we just provide a function form which lexically binds |this|?

Thats not the only common case. It might be the most common, but I see a lot method pointers that need binding too. If you saw my proposal in the other thread, I was hoping to use this binding operator to separate the lexical binding of this from the shorter function syntax.

# Kevin Smith (13 years ago)

Thats not the only common case. It might be the most common, but I see a lot method pointers that need binding too.

Can you post an example?

# Kevin Smith (13 years ago)

Russell, I looked at the other thread more carefully and now understand what you're saying. Can't we use a bound |this| function for all these cases?

needsCallback(x => foo.bar(x));
needsCallback(x => this.bar(x));

// Suppose for a moment that -> also binds |this|
needsCallback((x, y) -> {

if (x) this.doX(x); else this.doY(y); });

It seems that with bound |this| functions, the need to explicitly bind |this| tends to fall away.

# Nadav Shesek (13 years ago)

On Wed, Mar 28, 2012 at 9:57 PM, Kevin Smith <khs4473 at gmail.com> wrote:

It seems that with bound |this| functions, the need to explicitly bind |this| tends to fall away.

This is true for function literals that needs to be bound to the this context in the scope where they're created, but not very helpful for binding a function reference or for binding to objects other than this. In my own code, the first case is quite common - mostly functions that's defined ones and gets bound to multiple objects. That being said - the most common case I encounter is the anonymous-function-bound-to-this scenario.

# Nadav Shesek (13 years ago)

BTW, there's also some discussion on a bind operator at a ticket I opened on CoffeeScript's tracker, jashkenas/coffee-script#2136 (slightly based on the syntax proposed on "Sugar for *.prototype and for calling methods as functions" < esdiscuss/2012-February/020699>)

which might be related - tho the syntax itself is more CoffeeScript-y and probably less appropriate for ES6 (due to @ having a different meaning)

# Russell Leggett (13 years ago)

On Wed, Mar 28, 2012 at 3:57 PM, Kevin Smith <khs4473 at gmail.com> wrote:

Russell, I looked at the other thread more carefully and now understand what you're saying. Can't we use a bound |this| function for all these cases?

needsCallback(x => foo.bar(x));
needsCallback(x => this.bar(x));

// Suppose for a moment that -> also binds |this|
needsCallback((x, y) -> {

if (x) this.doX(x); else this.doY(y); });

It seems that with bound |this| functions, the need to explicitly bind |this| tends to fall away.

Yeah, I mean look - it may be that having short function with bound this and implicit return can get the job done. Of course, it seems so easy with just one argument called x. Its a little different if it looks more like:

needsCallback((event,data) => foo.bar(event,data));
needsCallback((element,index,array) => this.bar(element,index,array));

Would you shorten or put in dummy arg names?

needsCallback((e,d) => foo.bar(e,d));
needsCallback((a,b,c) => this.bar(a,b,c));

What if you didn't want to worry about the arguments? I mean, there's no reason you should have to make this know the contract between the function call and the callback params. I guess we could use rest params.

needsCallback((args...) => this.bar(args...));

But obviously that starts to seem like a code smell, especially if you have multiple:

doSomething({
  success: (args...) => this.success(args...),
  error: (args...) => this.error(args...)
});

In this case it doesn't really beat bind, and maybe it doesn't have to, but in relation to the short function syntax thread, it's possible that this makes sense as a way of composing different parts.

# Erik Arvidsson (13 years ago)

I find this proposal backwards. It requires an expeession as the right hand side. Alex proposed something similar a long time ago. He suggested using '!' instead of '.'. This is important because the common use case we want to solve is to make 'obj.foo.bind(foo)' be written as 'obj!foo'. With your proposal I have to do let f = obj.foo; obj::f which is even longer than the original.

Another important, but orthogonal part of his proposal was to have obj!meth === obj!meth

expression!propertyName

// desugars to

// WeakMap to cache the lookup. let objectMap = new WeakMap;

do { let object = expression; let map; if (!(map = objectMap.get(object)) { map = new Map; objecMap.set(object, map); } let result; if ((result = map.get("propertyName"))) return result; result = object.propertyName.bind(object); map.set("propertyName", result); result; }

One option would be to use the function instead of the property name as the key in the inner map.

# Russell Leggett (13 years ago)

On Wed, Mar 28, 2012 at 5:19 PM, Erik Arvidsson <erik.arvidsson at gmail.com>wrote:

I find this proposal backwards. It requires an expeession as the right hand side. Alex proposed something similar a long time ago. He suggested using '!' instead of '.'. This is important because the common use case we want to solve is to make 'obj.foo.bind(foo)' be written as 'obj!foo'. With your proposal I have to do let f = obj.foo; obj::f which is even longer than the original.

Yes, this was the way that my proposal worked as I mentioned it in the other thread (sorry, this is getting confusing now) === from my orginal post in the short function thread === //here the # acts as both a . and bind in one needsCallback(foo#bar) needsCallback(this#bar)

//in this case, it obviously doesn't access a property, it just does a bind needsCallback(this#function(x,y){ if(x){ this.doX(x); else{ this.doY(y); } }); //or with the new syntax needsCallback(this#(x,y)->{ ... });

I used # instead of !, but effectively the same idea.

Another important, but orthogonal part of his proposal was to have obj!meth === obj!meth

expression!propertyName

// desugars to

// WeakMap to cache the lookup. let objectMap = new WeakMap;

do { let object = expression; let map; if (!(map = objectMap.get(object)) { map = new Map; objecMap.set(object, map); } let result; if ((result = map.get("propertyName"))) return result; result = object.propertyName.bind(object); map.set("propertyName", result); result; }

One option would be to use the function instead of the property name as the key in the inner map.

Yes, this was something I mentioned to John Tamplin regarding his concern above about unregistering a handler.

I'm writing up a more detailed proposal that I will post soon.

# David Herman (13 years ago)

On Mar 28, 2012, at 2:19 PM, Erik Arvidsson wrote:

With your proposal I have to do let f = obj.foo; obj::f which is even longer than the original.

That's not a fair argument. There's no need for the let-binding; you can write

obj::obj.foo

or

::obj.foo

Now, you might feel that it's more intuitive for the latter form to be expressed with an infix operator. I'm sympathetic to that. But my operator is more expressive, because it can also express .call, which Alex's ! operator can't:

o1::o2.foo(x, y, z) ~= o2.foo.call(o1, x, y, z)

I would love to have built-in syntax for doing all three ABC methods (.apply/.bind/.call), so that's what I find appealing about the :: syntax. It's nice conservation of special forms that :: in conjunction with ... can accommodate all three. But perhaps we should explore two separate new forms.

Another important, but orthogonal part of his proposal was to have obj!meth === obj!meth

I'm not sure I have an opinion about this part yet. Can you explain the rationale?

# Erik Arvidsson (13 years ago)

On Thu, Mar 29, 2012 at 15:34, David Herman <dherman at mozilla.com> wrote:

On Mar 28, 2012, at 2:19 PM, Erik Arvidsson wrote:

With your proposal I have to do let f = obj.foo; obj::f which is even longer than the original.

That's not a fair argument. There's no need for the let-binding; you can write

obj::obj.foo

I'm not sure I follow? Replace obj with an arbitrary expression and it becomes evident that a let binding is needed

::obj.foo

I guess this one would work but I find it a bit strange to have this as prefix operator.

::object.foo.bar().baz

which is the same as

do { let tmp = object.foo.bar(); tmp::tmp.baz }

Now, you might feel that it's more intuitive for the latter form to be expressed with an infix operator. I'm sympathetic to that. But my operator is more expressive, because it can also express .call, which Alex's ! operator can't:

o1::o2.foo(x, y, z) ~= o2.foo.call(o1, x, y, z)

That is pretty nice but I think we covered the two most common uses by introducing super and spread already

I would love to have built-in syntax for doing all three ABC methods (.apply/.bind/.call), so that's what I find appealing about the :: syntax. It's nice conservation of special forms that :: in conjunction with ... can accommodate all three. But perhaps we should explore two separate new forms.

Another important, but orthogonal part of his proposal was to have obj!meth === obj!meth

I'm not sure I have an opinion about this part yet. Can you explain the rationale?

The classic use case that everyone runs into is addEventListener/removeEventListener.

eventTarget.addEventListener(type, this.handleFoo.bind(this)); ... eventTarget.removeEventListener(type, this.handleFoo.bind(this)); // OOPS