Generalizable Function Modifier Syntax

# Kevin Smith (11 years ago)

While working on async functions, it has become apparent to me that we are missing a generalizable syntax for function modifiers. The current precedent for function modifiers is generators:

function* ...
{ *name() {} }

Unfortunately, this precedent requires that all modifiers be punctuators. Sticking to that precedent would result in code whose meaning is obfuscated behind overloaded symbol-definitions, and would therefore be user-hostile, particularly for less experienced users.

We can get away with it for generators, because "*" is understood to mean "a sequence of zero or more" in a wide variety of programming contexts. In the case of async functions, we are, I think, not so lucky.

With that in mind, I'd like to present a modest proposal for generalizable function modifiers.

In the case of function expressions, function declarations, and methods, the choice is pretty clear:

modifier [NoNewLine] function ...
{ modifier name() {} }

e.g.

async function af() {}
{ async af() { } }

The hard part is arrow functions. One possibility would be to use another cover grammar and place the modifier to the left of the arrow function:

modifier [NoNewLine] Identifier =>
modifier [NoNewLine] ArgumentList =>

We could probably reuse some of the existing arrow function parsing strategy to back up the input stream or transform the AST.

Another possibility would be to place the modifier to the right of the argument list:

Identifier [NoNewLine] modifier => ...
ArgumentList [NoNewLine] modifier => ...

e.g.

x async=> {}
(a, b, c) async=> {}

This would be easier to parse, and would align with a potential "generator arrow":

x *=> {}

(Presuming that we can give up on arrows with empty parameter lists.)

Any thoughts?

# Brendan Eich (11 years ago)

Kevin Smith wrote:

async function af() {}
{ async af() { } }

This lines up with what Luke Hoban presented at the last TC39 meeting. So far, so good (but not a done deal by any means, of course). The main bone of contention is the use of ! in promises future-proposed syntax.

The hard part is arrow functions. One possibility would be to use another cover grammar and place the modifier to the left of the arrow function:

modifier [NoNewLine] Identifier =>
modifier [NoNewLine] ArgumentList =>

We could do this.

We could probably reuse some of the existing arrow function parsing strategy to back up the input stream or transform the AST.

It smells, but we're used to it!

Another possibility would be to place the modifier to the right of the argument list:

Identifier [NoNewLine] modifier => ...
ArgumentList [NoNewLine] modifier => ...

e.g.

x async=> {}
(a, b, c) async=> {}

This would be easier to parse, and would align with a potential "generator arrow":

x *=> {}

(Presuming that we can give up on arrows with empty parameter lists.)

Bletch, and don't multiple risks unnecesasrily by entangling with opposition to empty arrow param list elision.

# Kevin Smith (11 years ago)

Thanks, Brendan!

This lines up with what Luke Hoban presented at the last TC39 meeting. So far, so good (but not a done deal by any means, of course). The main bone of contention is the use of ! in promises future-proposed syntax.

"!" won't work, in my opinion. Besides being an eyesore, it is unfriendly to chaining because of the newline restrictions required by ASI. E.g. this won't work as expected:

getSomethingAsync()
!method1()
!method2()
!etc();

The hard part is arrow functions. One possibility would be to use

another cover grammar and place the modifier to the left of the arrow function:

modifier [NoNewLine] Identifier =>
modifier [NoNewLine] ArgumentList =>

We could do this.

Don't need the newline restriction in the second rule:

modifier [NoNewLine] Identifier =>
modifier ArgumentList =>

I was able to generically implement this syntax without too much trouble 1. Allowing default initializers in the arrow function head makes me nervous though, given Javascript's context-sensitive tokenization. Do you think that was a mistake?

In any case, I think this is the way to go for generic function modifiers!

I'll post some other feedback regarding async functions in the near future.