Arrow methods

# Sultan (6 years ago)

As the name suggests; An update to the grammar related to methods on objects/classes to support arrow methods:

today: {render() { return 'Hello' }} proposed addition: {render() => 'Hello'}

This could be some-what linked to class fields in the class variant; That is what does "this" refer to when used in a class.

# J Decker (6 years ago)
# Sultan (6 years ago)

The missing colon ":" is intentional.

# Isiah Meadows (6 years ago)

Not sure what the benefit here is:

  • You can do foo: () => bar for objects
  • You can do foo = () => bar for class instances using the public fields

proposal.

This leaves out self-binding, but you could always use a local variable if necessary. (It's like one extra line, maybe 3, and it's not common at all.)

# Sultan (6 years ago)

Consistency and sugar. Changing from arrow and non-arrow method is a diff between => where:

foo() {} mirrors foo: function () {} foo() => {} mirrors foo: () => {}

Also the "this" reference in the second variant is not the class instance i.e it is part of the shared prototype.

It has an added reach in usefulness when you consider nested classes:

class A { foo() { return class B { bar() => { return this // refers to instance A } } } }

This is not possible today without creating a self-like variable for bar to reference A's instance; Which is one of the points arrow functions addressed.

# Tab Atkins Jr. (6 years ago)

On Fri, Nov 16, 2018 at 12:42 PM Sultan <thysultan at gmail.com> wrote:

Consistency and sugar. Changing from arrow and non-arrow method is a diff between => where:

foo() {} mirrors foo: function () {} foo() => {} mirrors foo: () => {}

Yes, but note that the first one actually contains sugar - it lets you omit a decent chunk of characters (at bare minimum, nine) and puts the name next to the arg-list again, like how normal functions look.

The second lets you omit exactly one character. It also makes it look more like a named function declaration, while arrow functions are always name-less, so it's not helping you return to a "normal" form either.

Also the "this" reference in the second variant is not the class instance i.e it is part of the shared prototype.

It has an added reach in usefulness when you consider nested classes:

class A { foo() { return class B { bar() => { return this // refers to instance A } } } }

This is not possible today without creating a self-like variable for bar to reference A's instance; Which is one of the points arrow functions addressed.

Instance methods that don't refer to the instance are definitely the exception, not the rule. Reading this code, I would absolutely expect on first and probably second glances for this to be referring to the B instance, not the A instance. Binding A's this to a different name is actually a readability aid in this circumstance, unlike the many cases that arrow functions were designed to replace.

This looks to me like a decent argument against the suggestion. :/

# T.J. Crowder (6 years ago)

On Fri, Nov 16, 2018 at 9:52 PM Tab Atkins Jr. <jackalmage at gmail.com> wrote:

...while arrow functions are always name-less...

Minor nit-pick: Arrow functions are often named:

const foo = () => {
    console.log(foo.name);
    throw new Error();
};
foo();

Fiddle: jsfiddle.net/1gpbvx06

Running that, you'll see something like this in the console:

foo
Uncaught Error
    at foo ((index):35)
    at (index):3

(Edge doesn't show the stack trace in the console, but if you step into foo, it shows the proper name in the call stack.)

Search for SetFunctionName in the spec to find all the various places anonymous function expressions (both traditional and arrow) assign names to functions as of ES2015. (Basically: Anywhere the expression result is assigned to a variable, constant, or default parameter value; or when it's assigned to a property in an object initializer [but not when assigned to a property on an existing object].)

</nit-pick> ;-)

-- T.J. Crowder

# T.J. Crowder (6 years ago)

On Fri, Nov 16, 2018 at 8:42 PM Sultan <thysultan at gmail.com> wrote:

It has an added reach in usefulness when you consider nested classes:

class A {
  foo() {
    return class B {
      bar() => {
        return this // refers to instance A
      }
    }
  }
}

This is not possible today without creating a self-like variable for bar to reference A's instance; Which is one of the points arrow functions addressed.

It is, just not within the class construct:

class A {
  foo() {
    class B {
    }
    B.prototype.bar = () => {
      return this; // refers to instance A
    };
    return B;
  }
}

I agree with Tab Atkins Jr.: In your nested classes example, I'd expect this within bar to be the B instance, not the A instance. I think the more natural definition of that syntax (if it were adopted) would be a prototype function that is effectively auto-bound to the instance at construction time, like this common pattern today:

class B {
  constructor() {
    this.bar = this.bar.bind(this);
  }
  bar() {
    return this;
  }
}

In fact I could see some benefit to that syntax, since people use class fields for that use-case which can make mocking difficult.

But I'm not keen on that syntax with the semantics you're proposing.

-- T.J. Crowder

# Ron Buckton (6 years ago)

C# has a similar syntax for shorthand expression bodies (dotnet/roslyn/wiki/New-Language-Features-in-C%23-6#expression-bodies-on-method-like-members):

class Point {
  private int x;
  private int y;

  …

  // expression bodied getters (read-only)
  public int X => x;
  public int Y => y;

  // expression bodied method
  public Point Move(int dx, int dy) => new Point(x + dx, y + dy);
}

From: es-discuss <es-discuss-bounces at mozilla.org> On Behalf Of T.J. Crowder

Sent: Sunday, November 18, 2018 6:31 AM To: Sultan <thysultan at gmail.com>

Cc: es-discuss at mozilla.org Subject: Re: Arrow methods

On Fri, Nov 16, 2018 at 8:42 PM Sultan <thysultan at gmail.com<mailto:thysultan at gmail.com>> wrote:

It has an added reach in usefulness when you consider nested classes:

class A {
  foo() {
    return class B {
      bar() => {
        return this // refers to instance A
      }
    }
  }
}

This is not possible today without creating a self-like variable for bar to reference A's instance; Which is one of the points arrow functions addressed.

It is, just not within the class construct:

class A {
  foo() {
    class B {
    }
    B.prototype.bar = () => {
      return this; // refers to instance A
    };
    return B;
  }
}

I agree with Tab Atkins Jr.: In your nested classes example, I'd expect this within bar to be the B instance, not the A instance. I think the more natural definition of that syntax (if it were adopted) would be a prototype function that is effectively auto-bound to the instance at construction time, like this common pattern today:

class B {
  constructor() {
    this.bar = this.bar.bind(this);
  }
  bar() {
    return this;
  }
}

In fact I could see some benefit to that syntax, since people use class fields for that use-case which can make mocking difficult.

But I'm not keen on that syntax with the semantics you're proposing.

-- T.J. Crowder

# Andrea Giammarchi (6 years ago)

Once upon a time we've discussed the "thin arrow" so that `{method: () ->

this.name, name: 'any'}` would've worked as expected.

At that time it was considered "an arrow too far".