Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Fat Arrows and Classes-as-Prototype-sugar make a beautiful future for JavaScript
var stream = require("fake-stream-lib"),
Emitter = require("events").EventEmitter,
util = require("util");
// Today...
function Device( opts ) {
this.value = null;
// open an async stream,
// this will be called continuously
stream.read( opts.path, function( data ) {
// Update this instance's current value
// with the most recent value from the
// data stream
this.value = data;
// bind(this) is required for correct scope
}.bind(this) );
// Throttle the frequency of events emitted from
// this Device instance
setInterval(function() {
// Emit a throttled event
this.emit("event");
// bind(this) is required for correct scope
}.bind(this), opts.freq || 100 );
}
util.inherits( Device, Emitter );
Device.prototype.scale = function( low, high ) {
return this.value * ( high - low ) / 1023 + low;
};
// ------------------------------------------------------ //
// w/ Fat Arrow...
function Device( opts ) {
this.value = null;
// open an async stream,
// this will be called continuously
stream.read( opts.path, ( data ) => {
// Update this instance's current value
// with the most recent value from the
// data stream
this.value = data;
// bind(this) is no longer required
});
// Throttle the frequency of events emitted from
// this Device instance
setInterval(() => {
// Emit a throttled event
this.emit("event");
// bind(this) is no longer required
}, opts.freq || 100 );
}
util.inherits( Device, Emitter );
Device.prototype.scale = function( low, high ) {
return this.value * ( high - low ) / 1023 + low;
};
// ------------------------------------------------------ //
// w/ Fat Arrow & Class...
class Device extends Emitter {
constructor( opts ) {
super();
this.value = null;
// open an async stream,
// this will be called continuously
// This example uses the expression
// form of a fat arrow
stream.read( opts.path, data => this.value = data );
// Throttle the frequency of events emitted from
// this Device instance
setInterval(() => {
// Emit a throttled event
this.emit("event");
}, opts.freq || 100 );
}
scale( low, high ) {
return this.value * ( high - low ) / 1023 + low;
}
}
@rwaldron

This comment has been minimized.

Copy link
Owner Author

rwaldron commented May 10, 2012

For example purposes only, please refrain from pedantic nit-wittery.

@isaacs

This comment has been minimized.

Copy link

isaacs commented May 10, 2012

Oh, come now, @rwldrn, you know we can't refrain from such things. ;)

Srsly, though, these two features are actually pretty good, imo. With classes and arrows, you should hardly ever see the word function in your JavaScript, which will be a blessed improvement.

@rwaldron

This comment has been minimized.

Copy link
Owner Author

rwaldron commented May 10, 2012

@isaacs <3

@rwaldron

This comment has been minimized.

Copy link
Owner Author

rwaldron commented May 10, 2012

@juandopazo made this: https://gist.github.com/2654352 which adds another version that uses destructuring/default params :D

@dherman

This comment has been minimized.

Copy link

dherman commented May 10, 2012

<3z

@aackerman

This comment has been minimized.

Copy link

aackerman commented May 10, 2012

A very good example of some great things that are coming to JS

@angus-c

This comment has been minimized.

Copy link

angus-c commented May 10, 2012

can't you just do this?

stream.read( opts.path, data => this.value = data);

@rwaldron

This comment has been minimized.

Copy link
Owner Author

rwaldron commented May 10, 2012

@angus-c yessir. Updated!

edit: I updated the last example with a comment so we can see both forms in action

@chrisdickinson

This comment has been minimized.

Copy link

chrisdickinson commented May 10, 2012

@rwldrn Looks radical. A few questions:

  • Does the class syntax desugar to prototypes? For instance, if I have a large class and I'd like to move some methods out of the class, would something like the following still work?
class MyClass {
  constructor() { }
}

MyClass.prototype.action = (x, y) => {
  return x + y
}
  • Are anonymous classes allowed, or are they statement-level only? I can see pluses and minuses to both sides, so I'm just curious:
metaclass = (base) {
  return class extends base {
    someProperty(x) { return x }
  }
}
@juandopazo

This comment has been minimized.

Copy link

juandopazo commented May 10, 2012

@chrisdickinson at this point we're all speculating, but the answer to both your questions should be "yes".

@rwaldron

This comment has been minimized.

Copy link
Owner Author

rwaldron commented May 10, 2012

@chrisdickinson the last time I asked, I was told that, yes class syntax does create the function object that you expect today, so that should work exactly as you'd hope it would. Perhaps @dherman can confirm this for us

@dherman

This comment has been minimized.

Copy link

dherman commented May 10, 2012

Yes, absolutely.

One point of caution, though: you used a fat arrow for the action method. That won't work if you want to refer to this -- it so happens that your action method ignores this, so it's not a problem in this case. But in general you don't want to use fat arrow for methods, you want to use it for callbacks.

For methods, I really super duper double triple want thin arrow:

MyClass.prototype.anotherAction = (x, y) -> {
    return this.quux() * x + y;
}

Dave

@dherman

This comment has been minimized.

Copy link

dherman commented May 10, 2012

Oh, and the answer to the second question is also "yes" -- classes define first-class constructor functions, just like always. Both of your questions point to why everyone who says "onoes teh Java!" is overreacting.

Dave

@aackerman

This comment has been minimized.

Copy link

aackerman commented May 10, 2012

@dherman YES PLEASE thin arrow for methods. I really hope there is enough support for thin arrow methods to make it into the spec.

@chrisdickinson

This comment has been minimized.

Copy link

chrisdickinson commented May 10, 2012

@dherman good catch re =>. This is a good use case for ->, I'd say.

@juandopazo @rwldrn this is great news. I'm a huge fan of the idea of anonymous class expressions (and desugaring!)

@juandopazo

This comment has been minimized.

Copy link

juandopazo commented May 10, 2012

I can live with function for methods. It's the nesting of functions inside methods that becomes noisy. Thin arrows make sense for consistency.

@chrisdickinson

This comment has been minimized.

Copy link

chrisdickinson commented May 10, 2012

@juandopazo I can see some potential for confusion. I'd like to be able to use the arrow syntax when adding prototype methods, but there's a pretty big gotcha when doing that as it stands. It's a case for either making => soft binding (losing this when called against an object (or with apply, call, or bind)), or ->.

@chrisdickinson

This comment has been minimized.

Copy link

chrisdickinson commented May 10, 2012

Or going the python route and exposing the original function somehow (boundmethod.im_func is how they do it); though I'd rather fix the problem in a more javascript-y way.

@angus-c

This comment has been minimized.

Copy link

angus-c commented May 10, 2012

@dherman

This comment has been minimized.

Copy link

dherman commented May 10, 2012

I'm afraid soft bind will just never happen. I've argued against it for programming reasons, but it doesn't even really matter; the fact is it can't be implemented without making every call in the entire language more expensive. That would make the whole web slower, and JS engine implementers won't do it.

Dave

@domenic

This comment has been minimized.

Copy link

domenic commented May 10, 2012

<3

Re: thin arrows for methods. An alternative that has come up is using method shorthand in combination with the .{ operator:

Device.prototype.{
  scale( low, high ) {
    return this.value * ( high - low ) / 1023 + low;
  }
};

This has the added benefit (in the current TC39-approved status quo) that methods created using method shorthand get access to super. But, I believe as of last count .{ is not TC39-approved.

@polotek

This comment has been minimized.

Copy link

polotek commented May 11, 2012

I'm warming up to classes. The rest I'm still not crazy about.

@MarcDiethelm

This comment has been minimized.

Copy link

MarcDiethelm commented May 13, 2012

Omg, no fat arrows please!! On non-English keyboards the equals sign is often a character requiring shift to type. Thin arrow is better in that respect.

@angus-c

This comment has been minimized.

Copy link

angus-c commented May 13, 2012

@juandopazo

This comment has been minimized.

Copy link

juandopazo commented May 13, 2012

And English keyboard require shift for " which I'm sure it's written more often than function or =.

Non-English keyboard usually suck for coding anyway. Spanish-Spain keyboard requires Alt-Gr for both types of brackets. Alt-Gr! Fortunately there's the Latinamerican keyboard that looks a little more like the English one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.