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.
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 ;) ).
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.
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.
At one point I had memorized the corner cases* of `this` for the pointless reason of stumping people who thought they knew it. The only thing it really taught me was to avoid it.
*My favorite is "what does `this` point to when running `eval()`"? The current context. "What if you assign `eval` to a variable and then use that?" The global context.
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.
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.
> 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."
There is nothing that this proposal does that cannot be done today. It brings nothing new to the table aside from operator noise. I hope the committee pushes against these exotic features, like the bind operator or the pipe operator.
> 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.
No it's not. explicit != painful .
Do people really want to end up with a spec of the size of C++ spec ?
Even with arrow functions, it's pretty frequent to have to write things like `...on('event', evt => this.onEvent(evt))` where `on('event', ::onEvent)` would be quite nice.
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)
> 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.)
It has different semantics. Your code is equivalent to a `forEach` call, not `map`. Calling `map` returns a new array containing the results of the callback, while a for loop or a `forEach` don't.
Wow, what an improvement! In fact, why don't we just drop keywords altogether and adopt APL-like syntax for better code concision? Here, let me offer an example of how superior APL is:
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.
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.
Using that argument, you could say that every mathematical operation can boil down to addition and subtraction, because multiplication, exponentiation, and division are just flavors of those two operators. However, they're really convenient and I think that if an operator adds enough convenience it's worth the overhead of a new operator.
You can argue that the new bind operator isn't so convenient compared to the .bind syntax, but your argument is a bit weak.
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.
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.
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.
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.
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.
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