
ECMAScript bind operator proposal - networked
https://github.com/tc39/proposal-bind-operator
======
boubiyeah
The "this" keyword in JS has very bad characteristics and is full of traps.

I really wish we could stop building on top of this abomination (fake ES6
classes, binding, etc)

The |> operator (chaining of regular functions) would be so much better to
program with. We don't need both.

[https://github.com/mindeavor/es-pipeline-
operator](https://github.com/mindeavor/es-pipeline-operator)

~~~
_greim_
It's a pipe dream though. I mean, I wish an omnipotent, omni-benevolent
dictator would force everyone to stop using `this` and refactor it out of all
existing code as much as the next guy, but until that happens, the best path
forward is to _pave the cow paths_ and make the ugly parts easier to deal
with.

~~~
spion
Its just not taught correctly. `this` is the hidden function argument passed
by putting it left of the dot; from that, everything else follows.

~~~
groovy2shoes
Which is, of course, the same way `this` or `self` works in virtually every OO
language.

I honestly thought this was common knowledge, and not that hard to grasp. How
else is `this` being taught?

~~~
drewgross
The difference is the JS has late binding.

    
    
      myObj.myMethod();
    

Has different semantics than

    
    
      var x = myObj.myMethod; 
      x();
    

Which causes code like:

    
    
      myList.map(myObj.myMethod);
    

to behave somewhat unintuitively.

~~~
groovy2shoes
Your examples don't need late binding to have different semantics — dynamic
dispatch will suffice. That's not different from any other OO language (except
perhaps in C++ _for non-virtual methods_ ). That's how we get polymorphism out
of subtypes, after all: methods are resolved based on the dynamic value of the
receiver at runtime, yielding single dynamic dispatch. Regardless of language,
the `this` or `self` reference within a method _always_ semantically behaves
as if it were an additional parameter (except in typed languages where the
variance under the subtyping relation is reversed, iirc), and is often
implemented as such, albeit usually implicitly.

Of course, late binding implies dynamic dispatch, but the reverse isn't true.
On the other hand, almost every untyped OO language uses late binding (I can't
even think of one that doesn't, off the top of my head...), as do some typed
languages (those that target the .NET CLR, for example), so even with your
stronger assertion JS far from unique in that regard.

That behavior is standard fare for OO. If anyone finds it tricky, I find it
more likely that the struggling programmer has yet to internalize OO than that
JS is doing something strange (in this particular case, I mean... JS does
plenty of strange shit otherwise ;) ).

~~~
spion
The difference is that JS has _no_ binding, yet it still allows for first
class methods. Thus the OO "illusion" (object owns the methods) is broken:
there are no methods, just functions that take an argument named `this`, in a
slightly weird way, only when attached to records.

~~~
groovy2shoes
> The difference is that JS has no binding ... just functions that take an
> argument named `this`

Associating a name with a value is precisely what _binding_ is.

Frankly, though, I don't understand this comment _at all_. Care to clarify for
me?

~~~
prodigal_erik
In Python

    
    
      b = foo.bar
      b()
    

correctly invokes the bar method of the foo object. In JavaScript, you have to
write

    
    
      let b = foo.bar.bind(foo)
    

because foo.bar gives you a function (not a method) that doesn't remember
which object it came from.

~~~
groovy2shoes
I'm aware of what you have to write in JS, and I'd argue that that's the
behavior that's to be expected. I'm actually more surprised by Python's
behavior here. Lua works the same way JS does, as does Common Lisp.

------
scottfr
With arrow functions released and class properties likely to be approved soon,
this has minimal value and is probably not worth the cost of the extra
complexity to the language.

~~~
JasonSage
I respectfully disagree.

It all has to do with this line: "By providing syntactic sugar for these use
cases we will enable a new class of "virtual method" library, which will have
usability advantages over the standard adapter patterns in use today."

Essentially, you write functions that provide a certain behavior without being
coupled to a specific class, so you can have a 'map' method that is called the
same way no matter what you're mapping over.

Right now functional libraries like static-land, ramda, sanctuary, etc. are
working hard to provide these functional primitives but it's still painful to
write readable code that uses these.

It's also worth pointing out that directly importing methods here is more
efficient than importing entire classes if you're not using one of those
emerging build systems that does very good tree-shaking.

This is the closest JavaScript is going to get to letting you write your
behavior as a suite of functions separately from specific classes—it's like a
step removed from typeclasses.

~~~
sebdd
Wouldn't a pipeline operator [1] be a more interesting solution for this
instead of adding syntax that relies on the `this` keyword?

[1] [https://github.com/mindeavor/es-pipeline-
operator](https://github.com/mindeavor/es-pipeline-operator)

~~~
qwertyuiop924
No. Pipelining is handy, but not necessary. This binding is a well-known pain
point in JS.

------
rfw
Neat! Extension methods and getting rid of "var that = this;" in one!

It seems that it also extends to full expressions on the right-hand side of
::, so you can even do, for using Array operations over things that look like
arrays but not quite:

    
    
        document.querySelectorAll('p')::([].map)(f)
    

instead of:

    
    
        [].map.call(document.querySelectorAll('p'), f)
    

(replace [].map with Array.prototype.map if it feels less gross)

~~~
tomatsu
This also works, by the way:

    
    
        [...document.querySelectorAll('p')].map(f)
    

In the future, NodeList could extend Array which would make these workarounds
redundant. Extending Array was made possible by ES6.

Anyhow, I think having some kind of extension methods would be great.

~~~
gsnedders
> In the future, NodeList could extend Array which would make these
> workarounds redundant.

It would break the web, unfortunately. (We've experimented with
NodeList.prototype.__proto__ being Array.prototype instead of Object.prototype
and it breaks sites, and ES6's extends notion implies that.)

------
yladiz
Amongst other things, the bind operator is very useful for React, so instead
of having to call _this.handleChange.bind(this)_ you can just call
_::this.handlechange_. As in, you can type this: _< input
onChange={::this.handleChange} />_. It's a minor thing, but I prefer it a lot
more than the explicit bind syntax. There are other cases as well, but since
I'm doing a lot of work in React at the moment, having that is really
convenient.

~~~
marcusarmstrong
I've found using properties (which auto-bind) to be an easier solution.

------
xbdjdjfksmcf
This proposal really deserves the "kill it with fire" label. Adding new
operators to do things that are already possible will only serve to make the
language more complicated and code written in JS more difficult to understand
and maintain. JS's minimalism is its greatest strength.

~~~
qwertyuiop924
"Minimalism." Right.

Lua is minimal. Scheme is minimal. Forth is minimal. Hell, Brainfuck is
minimal. JS isn't.

------
aikah
I don't think Ecma-script needs new operators ,especially the kind of
operators that will make it look like C++ , just to save a few key types.
There needs to be a balance. A balance between all these tricks and
readability.

~~~
masswerk
This. – More important than any language features is the conceptual space of a
given language. JS used to be (very) good at this, but is losing terrain
lately.

------
TheAceOfHearts
This proposal has been around for a while. I try keeping an open mind, since
I've been wrong about many other syntactic features... But I just don't see
this being that useful; none of the examples seem particularly compelling.

It's also worth noting that most (?) modern browsers already bind log to
console. At least Chrome, Firefox, and Safari all support it. I don't have a
Windows machine so I can't confirm if Edge supports it. Same goes for Node.

    
    
        [1, 2, 3].forEach(console.log)

~~~
terinjokes
> It's also worth noting that most (?) modern browsers already bind log to
> console.

And it should be in all modern browsers soon[1], as `window.console` is now a
namespace: [https://console.spec.whatwg.org/#console-
namespace](https://console.spec.whatwg.org/#console-namespace)

[1]: [https://developer.microsoft.com/en-us/microsoft-
edge/platfor...](https://developer.microsoft.com/en-us/microsoft-
edge/platform/issues/9392959/)

------
WhitneyLand
Thinking about new language features in terms of, what percentage of JS
developers will understand it and what percentage will be confused by it,
there's an argument for just leaving things be.

I would bet 3 years from now less than half of developers will be able to
explain :: in an interview. Not that a much higher percentage could explain
'this' but what's done is done.

------
mschuetz
I don't know, I kinda like ".bind(this)" to bind the current scope to a
callback.

    
    
      class Vector{
      	constructor(x = 0, y = 0, z = 0){
      		this.x = x;
      		this.y = y;
      		this.z = z;
      		
      		setTimeout(function(){
      			console.log(this.x + ", " + this.y + ", " + this.z);
      		}.bind(this), 10);
      	}
      };
      
      var v = new Vector(1, 2, 3); // prints 1, 2, 3
    

Edit: Ok I can see this be potentially useful for function chaining, I just
don't do that very much.

~~~
erydo
Your own example is more concisely covered by arrows, which are already
available:

    
    
      class Vector {
        constructor(x=0, y=0, z=0) {
          this.x = x;
          this.y = y;
          this.z = z;
          setTimeout(() => console.log(this.x + ", " + this.y + ", " + this.z), 10);
        }
      }

------
entelechy
there are couple libraries that are build on top of this proposal:

[https://github.com/jussi-kalliokoski/trine](https://github.com/jussi-
kalliokoski/trine)

[https://github.com/roobie/mori-ext](https://github.com/roobie/mori-ext)

[https://github.com/thisables/curry](https://github.com/thisables/curry)

~~~
codecurve
Already had some time on the front page on HN today, but I just released
[https://zaphod.surge.sh/](https://zaphod.surge.sh/) which uses it.

------
kinkdr
Does anyone know the history behind "this"?

Is there any other language that uses "this" to denote "current context"?

~~~
gsnedders
There are plenty of languages which have an (implicit or explicit) argument
called something like "this" or "self" where the semantics of a x.y() call are
"look up y on the x object, call it with x as the this argument". C++
fundamentally works like that (the look-up is compile time in the case of non-
virtual functions, but like JS at runtime for virtual functions), Python,
Java, etc.

The oddity with JavaScript is two-fold: firstly, the fact that it passes the
global object (in non-strict code) given an z() style call (v. x.y() above);
secondly, the fact that you can call a function with an explicit this argument
using Array.prototype.call or Array.prototype.array.

What feels far more odd than that, though, is what the DOM does. It often acts
as if there's been a method call, whereas in reality it's just called with an
explicit this argument from C++. If you view a method dispatch as being a
message (à la Smalltalk, a large influence on JS) then obviously an event's
target is invoked as a message to the event. I obviously can't comment if
that's what Brendan was thinking, but it seems like an obvious analogue.

------
darawk
Personally i'd much prefer a currying syntax to a binding syntax.

const add1 = add::1

const createUser = post::('/user', authToken)

