back

by masswerk·12y ago·view on hn ↗
Great!

A few things that are rather addressing the Harmony proposal:

- `this` in arrow functions: Now this is breaking the standard behavior AND strict mode. I understand that we're running out of reserved words for this, but maybe it shouldn't have been `this` with different semantics. (I would expect all (near-)future extensions to be compliant with strict mode.)

- explicit `set()` and `get()` methods of Maps and WeakMaps: Why make them explicit and not implicit getters and setters (by subscript) like with associative arrays? Why another approach for the same thing?

These parts of the proposal are prone to cause some irritations, since they are adding duplicate behavior or syntax to existing approaches ...

Edit: I do understand that using subscripts in assignments to Maps and WeakMaps would produce some inconsistency on the other hand, since these subscripts would not translate to names (or rather to some hash-signature), so there's always a trade-off.

4 comments
Arrow functions don't break anything, they just add a little bit of complexity. And trust me, once you start using them, you'll never go back. That is one thing that TC39 absolutely got right; it solved a direct pain point in JS code and it's far easier to write good code with it.

I work on the Firefox Debugger, and all the devtools use ES6 extensively, especially arrow functions. They aren't confusing. Almost always, `this` refers to the object instance that you are working on, and arrow functions allow you to do quick functional programming inside the methods. It's beautiful.

Yeah, pretty much the only time you want non-arrow functions is for prototype methods (but once ES6 classes are implemented, you can use that syntax and it will be less verbose anyways). In almost every other case you either don't care about `this` or you want to use the containing function's `this` value. Arrow functions are perfect for these cases.
I would just point out the ambiguity while working with legacy code and ES6 applications. (A separate name would have been fine. But of course, there is the reserved names problem.)

From a practical perspective, we will have to deal with IE 8 and co for another 10 years at least. So we will have to "come back" all the time.

Hmm, reading the Harmony specs, an arrow function asserts ' typeof () => {} === "function"' and 'Object.getPrototypeOf(() => {}) === Function.prototype', but is not subject to `apply` and `call` (for obvious reasons).

Isn't this an issue with patterns, where an object is applied to a callback? It would introduce extensive testing, whether the callback was supplied as a regular function or (erroneously) as an arrow function (which would raise an error). Using try-catch for this would send the whole construct out of JIT-context at the other hand, so it isn't a favorable option.

Note: You may still use `call` and `apply` on them to supply arguments, but you may not change the this-object. (So, they are still subject to these calls. But this does not affect the use-case given above, where an object would be applied to a callback.)
But the same `this` will have different semantics, depending on the context (is it a function or object, or is it an arrow function?). Also, strict mode will be ignored for this (rather than overriding standard behavior). This is introducing ambiguity in two separate fields.

A not-so-serious proposal: Since everyone is overwriting the variable "self", we could reuse the variable "parent" for the same reasons in this case.

One reason to not make get() just be [] is that people wanted some methods on Map and WeakMap.

Say you have a Map named 'm' and you do m.clear(). Keep in mind that '.' is just syntactic sugar in JS, so this is by definition the same as m["clear"](). But now you have to worry about what happens if someone uses "clear" as a key for the Map. Does that make it impossible to clear the map? Impossible to retrieve the key? Reinstate the e4x behavior where x.y() and x.y.call(x) would do different things? Something else?

These concerns, which come up all the time with the use of objects as associative arrays, are why Map and WeakMap have explicit getter/setter methods. That way you can tell when you're working with the map part and when you're just treating it like an object with methods (clear, forEach, entries, keys, size, values) on it.

With regard to arrow functions, I'm a big fan of how CoffeeScript does it:

-> no special consideration for 'this', works like function()

=> binds 'this' to parent's 'this'

In my view on `this`, changing the semantics would always harm the generality of functions as first class entities. In case I would assign a function to an object as a method, what would this mean for the semantics of `this`? Evaluating the this-object just as late as possible gives a general approach that isn't prone to fail. By changing semantics, we're always introducing some edge-cases, for which there would have to be special behavior and constraints to be defined. Even with binding there would have to be some constraints to be added. (We have been doing great things with the current implementation for nearly 20 years by now, so it can't be that wrong.)

Personally, I would suggest the introduction of another variable, providing a "sticky this", which would stay bound to the this-object of the scope, the function was declared in. But what would be the reserved word to be used for it? (This would have to be restricted to arrow-functions, since there would be inconsistencies when assigning a method to an other object.)

It also makes the arrow shorthand less useful.

Instead of -> {...} replacing function() {...}

We get => {...} replacing (function() {...}).bind(this)

Why should the less common case get the more convenient syntax? Especially considering when we already have Function.prototype.bind to do this. How could they possibly agree on this but not the thin arrow?

There has been some discussion lately of JS being too verbose – this seems to be adding semantic sugar to address this. But introducing ambiguous semantics is quite an other thing.
I really hate the technical choice TC39 made with the arrow function. IT should have been a replacement for ANY kindof function. This is a total let down. Coffeescript syntax makes way more sense.
How does an arrow function's implicit bind(this) poses a problem or limits generality? (Honest question; I'm not a JS wizard.)
> How does an arrow function's implicit bind(this) poses a problem or limits generality?

Well you cant use it unbound. I dont want to declare functions bound to a scope I want a quick way to declare functions.

Dear down-voter: The case of an arrow function asserting the type "function" and its prototype being `Function.prototype`, while not being subject to `call` or `apply` (for `this` being lexically bound to the parent object) is a practical case of introducing extra constraints – think of callbacks and the use of `apply` or `call` on them. (See the Harmony specs.)

So this is a) a personal view on this (as pointed out clearly) and b) not raised deliberately.

Edit: I think, explicitly asserting the binding by an assignment ("var that = this;") isn't the worst option and you may always trace back the variable to the binding-point. It may be an extra line of code, but we can live with that perfectly.
For set() and get(), I'm betting its because you can override the handling of attribute accessors on an object--this avoids that confusion.
Or it could be some kind of "cargo cult" from the implementation in an other language, considering some of the popular writings and discussion in the last time. Personally, I would prefer JS "doing it the JS-way", rather than overloading paradigms by introducing implementation schemes from other languages. (Is JS prone to become a "Frankenstein language"?)

I'm hoping you're right with your guess, regarding the motivations behind it.