let function

# Alexander Jones (10 years ago)

Propose adding support for

let function foo() {};

which would have the equivalence of:

let foo = function foo() {};

The idea is to support the normal scoping of let, but without forcing you to repeat yourself when naming the function, whilst still having the function's name property be set.

This would trivially extend to const and var. Also, possibly class.

# Kevin Smith (10 years ago)

Why not use a function declaration instead?

# Andrea Giammarchi (10 years ago)

I guess 'cause that cannot be scoped, let's say in a for loop ... but yeah, I think that's not the most needed thing in the language right now, yet another shortcut with double reserved words one after the other

# Domenic Denicola (10 years ago)

They can, in fact, be scoped in a for loop.

# Alexander Jones (10 years ago)

Yep, that's the reason. It's invalid with 'use strict' to put function declarations inside an if or for block, and function declarations get hoisted.

Alternatively, as we have object shorthand notation, e.g.

{
    foo() {},
}

that does not require the function keyword, yet still acts like a function, expresses a property named foo that is a function with name property "foo". So maybe in the same spirit we could also consider

let foo() {};

But generators would look a bit weird without the function keyword...!

let *foo() {}

Agree this is not exactly the most pressing issue, but it seems easy to implement as it has trivial equivalence to existing language (unforeseen grammar ambiguities notwithstanding!), and having to repeat the name when defining scoped functions is a bit of a wart IMO.

# Domenic Denicola (10 years ago)

Yep, that's the reason. It's invalid with 'use strict' to put function declarations inside an if or for block

This is just false.

# Alexander Jones (10 years ago)

That's not what I see, in strict mode at least, which I assume most people consider de facto by now!

From V8:

SyntaxError: In strict mode code, functions can only be declared at top

level or immediately within another function.

Similar error from SpiderMonkey.

# Domenic Denicola (10 years ago)

Not all browsers have implemented the spec yet. But you should read the spec before proposing changes to it!

# joe (10 years ago)

Hay, I've not read all of the spec, and I've implemented much of it. :P

# Andrea Giammarchi (10 years ago)

not, in fact, in a backward compatible way, unless transpiled.

# Bergi (10 years ago)

Alexander Jones schrieb:

On Thursday, May 14, 2015, Domenic Denicola <d at domenic.me> wrote:

They can, in fact, be scoped in a for loop.

That's not what I see, in strict mode at least, which I assume most people consider de facto by now!

From V8:

 SyntaxError: In strict mode code, functions can only be declared at top

level or immediately within another function.

That's ES5. In ES6, function declarations are allowed in blocks - with the new block scope semantics. This was only possible as ES5 strict mode held that spot open so now it doesn't break anything :-) Yes, it will need a while until people get accustomed to that.

Bergi

# Alexander Jones (10 years ago)

Ah, thanks for explaining! What about the Temporal Dead Zone of let, or const binding semantics, for those of us who are obsessive enough to desire that kind of thing everywhere?

# Andrea Giammarchi (10 years ago)

like I've replied to Domenic, you need to transpile if you want function declaration block-scoped backward compatible and all other ES6 goodies.

babeljs would be my pick: babeljs.io

Best

# Garrett Smith (10 years ago)

On 5/14/15, Alexander Jones <alex at weej.com> wrote:

Ah, thanks for explaining! What about the Temporal Dead Zone of let, or const binding semantics, for those of us who are obsessive enough to desire that kind of thing everywhere?

Let a constructive discussion about this proposal take place.

"The specification," can most reasonably be taken among programmers to mean "the latest version of specification" not "draft specification" or "proposal". Evangelists and standards geeks tend to miscall "draft" "specification" to the misfortunate effect that it misleads developers into believing that drafts are normative, final, etc. That's quite a bit worse than the abrasiveness and confusion seen here, but hopefully they can stop and a discussion can take place.

www.ecma-international.org/ecma-262/5.1/#sec-12

Because of these irreconcilable differences, the use of a FunctionDeclaration as a Statement results in code that is not reliably portable among implementations. It is recommended that ECMAScript implementations either disallow this usage of FunctionDeclaration or issue a warning when such a usage is encountered.

The decision for such wording probably came from discussions and time constraints of getting ES5 done. The problem of FunctionDeclaration arose from implementations in JScript (see "[MS-ES3EX]" and language extensions in Spidermonkey and others. It progressed to misstatements in presentations and books. For more on this, see "Named function expressions demystified".

# Alexander Jones (10 years ago)

Good points. All the more reason to throw out declarations as statements in favour of let/const/var, which we all have to understand well anyway, for other types of variable.

# Ron Buckton (10 years ago)

I proposed something similar to this among the folks investigating decorators for ES7:

jonathandturner/decorators#17

In this case, it was for a const function, as a means to allow a decorator on a function declaration, as adding the const (or let) would introduce TDZ and set the right expectations for how decorators would be executed.

# Kevin Smith (10 years ago)

Good points. All the more reason to throw out declarations as statements in favour of let/const/var, which we all have to understand well anyway, for other types of variable.

Declarations aren't going anywhere, and there is zero interest in "deprecating" them. You might want to spend a bit more time learning the spec or lurking before making proposals.

Hope that helps.

# Alexander Jones (10 years ago)

When I said throw out, I didn't mean deprecate. I meant like 'let is the new var' - an entirely optional programming choice.

I'm not sure what warrants that kind of hostility, but I knew enough of the spec to know that 'use strict' prohibited function declarations as statements, and that let and const had attractive, sound and intuitive semantics. I'm sorry if you feel that's an inappropriate basis for a mailing list post, but I disagree.

# Allen Wirfs-Brock (10 years ago)

On May 14, 2015, at 12:40 PM, Alexander Jones wrote:

Ah, thanks for explaining! What about the Temporal Dead Zone of let, or const binding semantics, for those of us who are obsessive enough to desire that kind of thing everywhere?

ES6 specifies that function declarations are allowed in blocks in both strict and nn-strict mode. In both cases they are block scoped and have essentially the same semantics (including a TDZ) as a let declaration.

In addition, Annex B people.mozilla.org/~jorendorff/es6-draft.html#sec-block-level-function-declarations-web-legacy-compatibility-semantics provides an extended semantics for block level function declarations in non-strict code. That semantics is for use in implementations that need to provide backwards compatibility with the non-standard block level function declaration behavior that was provided by various browsers.

# Michael Haufe (10 years ago)

As Perlis has said: too much syntactic sugar causes cancer of the semicolon. IMO, this is not much of a win given what is now available, especially with arrow functions and shorthand method definitions

# André Bargull (10 years ago)

On May 14, 2015, at 12:40 PM, Alexander Jones wrote:

ES6 specifies that function declarations are allowed in blocks in both strict and nn-strict mode.
In both cases they are block scoped and have essentially the same semantics (including a TDZ) as a let declaration.

There is no TDZ for block-scoped function declarations. Function declarations are basically hoisted to the top of the block.

# Allen Wirfs-Brock (10 years ago)

On May 14, 2015, at 3:39 PM, André Bargull wrote:

There is no TDZ for block-scoped function declarations. Function declarations are basically hoisted to the top of the block.

Ah right, I misspoke about on that point. block level function declarations are indeed hoisted to the top of the block.

# Alexander Jones (10 years ago)

Thanks for sharing. Are there any known, viable alternatives for decorators?

# Garrett Smith (10 years ago)

On 5/14/15, Kevin Smith <zenparsing at gmail.com> wrote:

Good points. All the more reason to throw out declarations as statements in favour of let/const/var, which we all have to understand well anyway, for other types of variable.

Declarations aren't going anywhere,

Getting rid of FunctionDeclaration was not proposed.

If the proposed let function idea is no good, is it because FunctionDeclaration-as-a-Statement is a better replacement? Or is there a better reason?

and there is zero interest in

"deprecating" them. You might want to spend a bit more time learning the spec or lurking before making proposals.

You go read the spec and lurk.

Hope that helps.

It obviously doesn't help at all.

Consistency in implementations would help. An easier-to-read ECMAScript specification would also help. Discussions like this can help when they point out the reality of what implementations do vs what the specification and its authors say vs what the so-called experts, and worse (W3Schools, etc) say.

# Brendan Eich (10 years ago)

I post this followup with some trepidation, as the es-discuss S/N ratio has dropped badly in recent weeks. Perhaps esdiscourse is doing better? Anyway, discussion fodder: @rauchg messaged me recently wondering why

let f = (x) => y;

could not be shortened to

let f(x) y;

This seems like a better shorthand to discuss, compared to let function (which function-in-block covers already, as noted).

# Bergi (10 years ago)

Brendan Eich proposed:

let f = (x) => y;

could be shortened to

let f(x) y;

Too confusing imo. I'd like to retain the fat arrow that effectively communicates the callability:

let f(x) => y;

It would work fine without parameters as well:

let f() => y;

let f => y;

Alternatively just use a single equals sign with a parameter list:

let f(x) = y let f() = y

(which almost looks like Haskell, hehe).

Bergi

# Alan Schmitt (10 years ago)

On 2015-05-19 06:09, Bergi <a.d.bergi at web.de> writes:

Alternatively just use a single equals sign with a parameter list:

let f(x) = y let f() = y

This looks very nice indeed.

Alan

# Steve Fink (10 years ago)

On 05/19/2015 12:23 AM, Alan Schmitt wrote:

On 2015-05-19 06:09, Bergi <a.d.bergi at web.de> writes:

Alternatively just use a single equals sign with a parameter list:

let f(x) = y let f() = y This looks very nice indeed.

That visually collides with destructuring for me.

let [a, b] = foo(); let {a, b} = foo(); let f(a, b) = foo(); # Very different

I almost expect that last one to use f as a custom matcher of some sort, given the previous two.

# C. Scott Ananian (10 years ago)

On Tue, May 19, 2015 at 12:24 PM, Steve Fink <sphink at gmail.com> wrote:

That visually collides with destructuring for me.

let [a, b] = foo(); let {a, b} = foo(); let f(a, b) = foo(); # Very different

I almost expect that last one to use f as a custom matcher of some sort, given the previous two.

Well there's an interesting proposal. As I understand it, this corner of the grammar is free, so custom matchers would be a possibility here.

I can imagine some interesting uses for custom data types, eg:

let pair(a, b) = foo(); // like let {head, tail} = foo(); but with custom type checking. let polar(radius, angle) = point(1, 2); // custom matcher can convert between coordinate respresentations

or even build a simple matching case statement for a recursive decent parser:

let for_statement(init, cond, incr) = input_text;

Does that spark ideas in anyone else?

# Brendan Eich (10 years ago)

C. Scott Ananian wrote:

On Tue, May 19, 2015 at 12:24 PM, Steve Fink <sphink at gmail.com <mailto:sphink at gmail.com>> wrote:

That visually collides with destructuring for me.

let [a, b] = foo();
let {a, b} = foo();
let f(a, b) = foo(); # Very different

I almost expect that last one to use f as a custom matcher of some
sort, given the previous two.

Well there's an interesting proposal. As I understand it, this corner of the grammar is free, so custom matchers would be a possibility here.

I can imagine some interesting uses for custom data types, eg:

let pair(a, b) = foo(); // like let {head, tail} = foo(); but with custom type checking. let polar(radius, angle) = point(1, 2); // custom matcher can convert between coordinate respresentations

or even build a simple matching case statement for a recursive decent parser:

let for_statement(init, cond, incr) = input_text;

Does that spark ideas in anyone else?

Sure, and we've had pattern matching on the agenda for a while (distinct from destructuring in ES6: refutable match, richer pattern language).

harmony:refutable_matching (arossberg: anything newer on github?) strawman:pattern_matching (older strawman from dherman)

I agree that let f(x) = y encroaches confusingly on pattern matching, not let-function declaration.

# Alexander Jones (10 years ago)

On 19 May 2015 at 02:02, Brendan Eich <brendan at mozilla.org> wrote:

This seems like a better shorthand to discuss, compared to let function (which function-in-block covers already, as noted).

function-in-block does not have the same semantics as the proposed "let function". It hoists, thus has no TDZ, and appears to preclude a reasonable decorator syntax behaviour, and it has no provisions for const binding, i.e. "const function".

let f(x) => y

appears attractive indeed, but by virtue of it being an arrow function, has lexical this and no prototype property. Also no generator syntax, unless I'm missing something?

Cheers

# Kevin Smith (10 years ago)

function-in-block does not have the same semantics as the proposed "let function". It hoists, thus has no TDZ, and appears to preclude a reasonable decorator syntax behaviour,

But that would not fix the decorator/function problem. Specifically, we would not want to have a situation where "let" functions are decorable but function declarations are not.

and it has no provisions for const binding, i.e. "const function".

A "const function" syntax was proposed during ES6 development and might still be an option.

# Mark S. Miller (10 years ago)

Yes. I proposed it and plan to do so again. Likewise with const classes. In both cases, it imposes additional tamper-proofing restrictions along the lines of the StrongScript proposal in order to support writing defensively consistent abstractions.

# Brendan Eich (10 years ago)

Your point about decorators vs. hoisting is good, everyone should keep it in mind. Still doesn't mean we can't add a special form for const function, as followups aver.

# Alan Schmitt (10 years ago)

On 2015-05-19 18:24, Steve Fink <sphink at gmail.com> writes:

On 05/19/2015 12:23 AM, Alan Schmitt wrote:

On 2015-05-19 06:09, Bergi <a.d.bergi at web.de> writes:

Alternatively just use a single equals sign with a parameter list:

let f(x) = y let f() = y This looks very nice indeed.

That visually collides with destructuring for me.

let [a, b] = foo(); let {a, b} = foo(); let f(a, b) = foo(); # Very different

I almost expect that last one to use f as a custom matcher of some sort, given the previous two.

It is actually how it works in Ocaml: in "let f p = …", p is a pattern, which may destructure tuples such as the pair (a,b) above, or other constructs as long as they are not part of an alternation (where several cases may occur).

Best,

Alan

# Brendan Eich (10 years ago)

Guillermo wondered whether we couldn't have

let f(x) { return x*x; };

as a shorthand for the block-bodied arrow

let f = (x) => { return x * x; }

The obvious question is how to enable expression bodies?

let f(x) x * x;

looks like it is missing the =>, but if we require that:

let f(x) => x * x;

then why not for the block-bodied case too, so readers are better reminded that this is from the outer scope, ditto arguments?

Decisions, decisions!