Function "name" property

# Matthew Robb (9 years ago)

After today's Twitter discussions surrounding babel, concise methods, and a functions name property I had a thought and I was curious if it had been discussed before.

Is there a very good reason that the "name" property of a function is not a well known Symbol property? My understanding is it's main use is for debuggers anyway. It just seems like it would be more in line with the rest of the spec.

​I think it would be best to put more distance between the name property of a function and it's binding​ (if any) to reduce any potential confusion. Making it a symbol property and (also my opinion) making it writable would help in reducing said confusion.

  • Matthew Robb
# Allen Wirfs-Brock (9 years ago)

On Feb 25, 2015, at 7:26 PM, Matthew Robb <matthewwrobb at gmail.com> wrote:

... ​I think it would be best to put more distance between the name property of a function and it's binding​ (if any) to reduce any potential confusion. Making it a symbol property and (also my opinion) making it writable would help in reducing said confusion.

The automatically provided ‘name’ property of function objects has the attributes writable: false, configurable true. That means that its value can be modified using Object.defineProperty or deleted using the delete operator. You just can’t modify it using the assignment (=) operator.

# Brendan Eich (9 years ago)

This doesn't address the symbol idea, but I don't see the motivation for that. A well-known symbol doesn't help usability or integrity. Matthew, could you please link to the twitter thread?

Anyway, the reason 'name' is a normal property identifier and not a symbol is because it's a de-facto standard of sorts, with some intersection semantics.

# Leon Arnott (9 years ago)

The twitter thread starts here: twitter.com/getify/status/570614952605560838 and basically boils down to the observation that this:

({ f() { return f; }}.f()) /* ReferenceError (probably) */

is not semantically identical to this:

({ f: function f() { return f; } }.f()) /* function f() */

That is, concise methods cannot seamlessly recursively call or reference themselves. (Personally, I feel like concise methods should be a binding within themselves in a manner identical to named function expressions, but if this has been discussed before and discarded then I understand.)

You may notice that both of the methods above have the same name, "f", in spite of one lacking the lexical binding. Formerly, named functions always (barring internal var statements etc.) had lexical bindings to themselves, and the whole ES6 function name inference dealie breaks this correlation. I don't think this is really an important issue, though - assuming that a .name property equated to a binding was not a safe assumption (especially since IE never implemented .name but did support the binding).

# Matthew Robb (9 years ago)

On Wed, Feb 25, 2015 at 11:09 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>

wrote:

The automatically provided ‘name’ property of function objects has the attributes writable: false, configurable true. That means that its value can be modified using Object.defineProperty or deleted using the delete operator. You just can’t modify it using the assignment (=) operator.

​My mistake, rather than check the spec I tried it in Chrome's console and the property descriptor was configurable: false.​

  • Matthew Robb
# Allen Wirfs-Brock (9 years ago)

On Feb 26, 2015, at 4:10 AM, Leon Arnott wrote:

The twitter thread starts here: twitter.com/getify/status/570614952605560838 and basically boils down to the observation that this:

({ f() { return f; }}.f()) /* ReferenceError (probably) */

is not semantically identical to this:

({ f: function f() { return f; } }.f()) /* function f() */

That is, concise methods cannot seamlessly recursively call or reference themselves. (Personally, I feel like concise methods should be a binding within themselves in a manner identical to named function expressions, but if this has been discussed before and discarded then I understand.)

You may notice that both of the methods above have the same name, "f", in spite of one lacking the lexical binding. Formerly, named functions always (barring internal var statements etc.) had lexical bindings to themselves, and the whole ES6 function name inference dealie breaks this correlation. I don't think this is really an important issue, though - assuming that a .name property equated to a binding was not a safe assumption (especially since IE never implemented .name but did support the binding).

Note that property names are restricted to being valid identifiers. Note of the following concise methods could possibly use their property name as a lexical binding:

let o = { 42() {}, " this is not an identifier"() {}, ""() {}, if() {}, Symbol.iterate {} };

We may have a universal way for functions to self reference themselves i post ES6.

# Matthew Robb (9 years ago)

On Thu, Feb 26, 2015 at 11:32 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>

wrote:

We may have a universal way for functions to self reference themselves i post ES6.

​+1 this!!!!​

  • Matthew Robb
# Andrea Giammarchi (9 years ago)

I miss you arguments.callee, specially in this "fat arrows era" where most of the time developers don't even care about removing listeners.

Apologies for the laud thought and Best

# Felipe Nascimento de Moura (9 years ago)

that's true! I miss that too! We are working on a framework for the company here, and sometimes, getting the callee would be really useful, and we simply can't!!! Removing the arguments.caller/calee could make more sense if, like other features, had been replaced by another syntax.

What was the main reason why caller/calee were removed?

# Andrea Giammarchi (9 years ago)

callee could be spec'd similar to super and transpiled or resolved statically instead of dynamically, but callee.caller or in general the function caller raised many security concerns, giving you the ability to reach objects you probably shouldn't have.

These two were different beasts, but callee for numerous reasons, and specially for anonymous and non referenced Object methods syntax, is really leaving a hole in the language, IMO

Best

# Mark S. Miller (9 years ago)

On Thu, Feb 26, 2015 at 10:52 AM, Andrea Giammarchi < andrea.giammarchi at gmail.com> wrote:

callee could be spec'd similar to super and transpiled or resolved statically instead of dynamically, but callee.caller or in general the function caller raised many security concerns, giving you the ability to reach objects you probably shouldn't have.

These two were different beasts, but callee for numerous reasons, and specially for anonymous and non referenced Object methods syntax, is really leaving a hole in the language, IMO

To respond to this, I searched in vain for the following message on es-discuss, only to find it in a private thread. This message helped contribute towards the syntactic direction we finally took, where allowable new meta-accesses are introduces by <keyword>.<identifier>, but only for

keywords that are not valid expressions by themselves. ES6 contains the first example of this in "new.target". Many thanks to David Herman for this generalization -- I didn't see it at all.

Note that most of the meta.* proposals I list below I am not advocating -- indeed I think most are probably bad ideas. I include them only as examples of what lexical context meta accesses could be soundly added to the language as special forms.

For the record:

---------- Forwarded message ---------- From: Mark S. Miller <erights at google.com>

Date: Fri, Jan 2, 2015 at 5:10 PM Subject: Re: Subclassing Builtins

[...] close but not quite. E has a lexical reflective access special form that gives quite a lot of access -- the "meta" keyword. The important features that make it non-objectionable:

a) Its usage patterns is to extract from it the more specific reflective access needed for each use. b) Its API is designed to encourage such authority division on use. c) It is understood and documented from the beginning as giving broad access, so hopefully no one will mistake it for providing less access than it does.

So, hypothetically, if, say, we introduced "meta" as such a special form to JS, then

"meta.arguments" could provide arguments. "meta.originalContructor" could provide the original constructor. "meta.callee" could provide access to the function it appears in. "meta.source" could provide access to the source code of the function it appears in. "meta.strictness" could be a boolean indicating the strictness of the code it appears in. "meta.environment" could provide a Map from variable name to value reflecting the lexical scope at the place it appears.

More dangerously but still plausibly "meta" could provide an object with the above fields. The reason it is more dangerous is that passing "meta" might give access to a field added in a later spec. The reason it is still plausible is that passing "meta" itself, unlike passing "arguments" or "meta.arguments", would be understood as passing broad access.

However, "meta.caller", as something that provide[s] access to the current activation's caller, must still be forbidden.

# Kevin Smith (9 years ago)

To respond to this, I searched in vain for the following message on es-discuss, only to find it in a private thread. This message helped contribute towards the syntactic direction we finally took, where allowable new meta-accesses are introduces by <keyword>.<identifier>, but only for keywords that are not valid expressions by themselves.

So, e.g. arguments.callee could be re-imagined as "function.callee" or something similar.

# Mark S. Miller (9 years ago)

yes, exactly. As a lexical special form, it violates no fundamental principle.

# Felipe Nascimento de Moura (9 years ago)

I remember of a point where it has been discussed about "levels" for the "use strict" flag. It was discarded, by the way, hehe

But it might be related to this, like "allowing" the detection of calees in the given scope or not.

I think it could be useful like this: Function.getMetaData(theFunction); to avoid back-compatibility problems

or perhaps, the existence of a new keyword (not so retro-compatible) of a scope. scope.calee; scope.source; scope.arguments;

ACTUALLY...the word "transient" is reserved in ES, so we could use this keyword, instead of scope...or is this a bad idea?!

I think it is not very cozy to read, something like this function(){ console.log( function.calee ); console.log( function.name ); }

,

# Allen Wirfs-Brock (9 years ago)

I send a new topic message about the following, but for some reason it seems slow getting to es-discuss. So, I'm trying it via a replay:

Here is a new proposal for some additional meta properties that should be considered for ES7 allenwb/ESideas/blob/master/ES7MetaProps.md

# Andrea Giammarchi (9 years ago)

FWIW, that looks great to me Allen, thanks for writing that down!

I specially like that it's going to take just about 22 years before arguments will be usable as Array ... eh eh eh, about the time :D

Best

# Mark S. Miller (9 years ago)

On Thu, Feb 26, 2015 at 2:17 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>

wrote:

I send a new topic message about the following, but for some reason it seems slow getting to es-discuss. So, I'm trying it via a replay:

Here is a new proposal for some additional meta properties that should be considered for ES7 allenwb/ESideas/blob/master/ES7MetaProps.md

For most of these, my first reaction is meh. They all make sense and violate no principle, but are they worth it?

I do not like the arrow function behavior. For anything named function.something occurring within an arrow function, I'd expect it to be about the lexically enclosing non-arrow function. I do not object to the idea that there be such a special form that is about the arrow function, but it needs to be spelled differently. I have no concrete suggestion though.

But function.next -- Current yield result is awesome! Bravo. It solves a problem which is otherwise really hard to express.

# Allen Wirfs-Brock (9 years ago)

On Feb 26, 2015, at 3:55 PM, Mark S. Miller wrote:

But function.next -- Current yield result

is awesome! Bravo. It solves a problem which is otherwise really hard to express.

Actually, another possible name for this that I want to put on the table is:

function.last --- the last value passed back via 'next'

# Allen Wirfs-Brock (9 years ago)

On Feb 26, 2015, at 3:55 PM, Mark S. Miller wrote:

For most of these, my first reaction is meh. They all make sense and violate no principle, but are they worth it?

I do not like the arrow function behavior. For anything named function.something occurring within an arrow function, I'd expect it to be about the lexically enclosing non-arrow function. I do not object to the idea that there be such a special form that is about the arrow function, but it needs to be spelled differently. I have no concrete suggestion though.

We have to work with the reserved words we have available, there really need to apply equivalently to all functions, arrow or otherwise defined. The only other available keyword that seems at all suggest of these use cases is 'in'

in.callee (or whatever) in.count. in.arguments

If we went that route I'd probably still stick with 'function.next' for that use case

# Jorge (9 years ago)

On 26/02/2015, at 13:10, Leon Arnott wrote:

Formerly, named functions always (barring internal var statements etc.) had lexical bindings to themselves,

Not always:

//Yes a= function f () { return f }; f=null; a() -> function f()

//No. Look ma, no binding! function f () { return f }; a=f; f=null; a() -> null

# Claude Pache (9 years ago)

Le 27 févr. 2015 à 02:04, Allen Wirfs-Brock <allen at wirfs-brock.com> a écrit :

On Feb 26, 2015, at 3:55 PM, Mark S. Miller wrote:

For most of these, my first reaction is meh. They all make sense and violate no principle, but are they worth it?

I do not like the arrow function behavior. For anything named function.something occurring within an arrow function, I'd expect it to be about the lexically enclosing non-arrow function. I do not object to the idea that there be such a special form that is about the arrow function, but it needs to be spelled differently. I have no concrete suggestion though.

We have to work with the reserved words we have available, there really need to apply equivalently to all functions, arrow or otherwise defined. The only other available keyword that seems at all suggest of these use cases is 'in'

in.callee (or whatever) in.count. in.arguments

If we went that route I'd probably still stick with 'function.next' for that use case

Allen

That one has just popped in my mind :-)

=>.arguments
# Mark Miller (9 years ago)

On Feb 26, 2015 5:04 PM, "Allen Wirfs-Brock" <allen at wirfs-brock.com> wrote:

...[arrow functions]...

If we went that route I'd probably still stick with 'function.next' for

that use case

Since we don't have arrow generator functions...

# Rick Waldron (9 years ago)

On Thu Feb 26 2015 at 8:22:55 PM Claude Pache <claude.pache at gmail.com>

wrote:

Le 27 févr. 2015 à 02:04, Allen Wirfs-Brock <allen at wirfs-brock.com> a écrit :

On Feb 26, 2015, at 3:55 PM, Mark S. Miller wrote:

For most of these, my first reaction is meh. They all make sense and violate no principle, but are they worth it?

I do not like the arrow function behavior. For anything named function.something occurring within an arrow function, I'd expect it to be about the lexically enclosing non-arrow function. I do not object to the idea that there be such a special form that is about the arrow function, but it needs to be spelled differently. I have no concrete suggestion though.

We have to work with the reserved words we have available, there really need to apply equivalently to all functions, arrow or otherwise defined. The only other available keyword that seems at all suggest of these use cases is 'in'

in.callee (or whatever) in.count. in.arguments

If we went that route I'd probably still stick with 'function.next' for that use case

Allen

That one has just popped in my mind :-)

    =>.arguments

I was thinking exactly this while I was reading Allen's post.

Would class method definitions use class.*? Seems like the wrong abstraction..? Maybe all functions and method definitions use function, while arrows use => (or whatever) to preserve correspondence to possible

outer function?

# Mark Miller (9 years ago)

Why do arrow functions need to reflect on themselves? I think it is more useful for all code "directly" inside a non-arrow function to be able to reflect on that non-arrow function. If I wrote an arrow function and then found I wanted it to reflect on itself, I'd be happier rewriting it as a non-arrow function than I would with either

  • the complexity of a whole new set of special forms for arrow functions to reflect on themselves, or
  • (as in the original proposal) making it more difficult for code in an arrow function to reflect on their containing non-arrow function.
# Andrea Giammarchi (9 years ago)

Mark many framewors/libraries/younameit attach listeners at construction time, there is where everyone feels like it's cool and fast and better, and shorter to use arrow functions, then they have to mix between removable listeners and not.

I personally pass objects as listeners, providing an handleMethod so that I never need to address functions or methods to be able to remove a listener via an event, unfortunately when nodejs was born developers didn't know this way of adding listeners so that's not even an option in node.

Having arrows functions with all these "refactoring caveats" doesn't feel smart because you always want to be able to re-schedule a setTimeout, you always want to be able to have a recursion without trusting the context that could be just undefined (or the global one if transpiled in older engines) and you always want to be eventually able to drop a listener in certain circumstances ... or at least, that's the reason I still try to avoid using arrows functions.

For "greppability sake", code consistency and reliability, a callee like feature would be a good solution for all cases.

We had this before, and it was useful. It got lost together with other things that were not as useful and secure at the same time.

Then if it's just me, feel free to ignore my thoughts on callee.

Best

# Allen Wirfs-Brock (9 years ago)

On Feb 27, 2015, at 8:00 AM, Rick Waldron wrote:

I was thinking exactly this while I was reading Allen's post.

Would class method definitions use class.*? Seems like the wrong abstraction..? Maybe all functions and method definitions use function, while arrows use => (or whatever) to preserve correspondence to possible outer function?

the point here is that they are all "functions", regardless of how they are declared. When we write foo(), we don't care whether 'foo' is was declared using a function declaration, or a concise method, or class, or arrow syntax. We only care that it is a "function" which is an object that can be 'called' with an argument list. That is the exact sense that the word 'function' should be interpreted for those proposed meta properties.

# Rick Waldron (9 years ago)

On Fri Feb 27 2015 at 11:56:04 AM Allen Wirfs-Brock <allen at wirfs-brock.com>

wrote:

On Feb 27, 2015, at 8:00 AM, Rick Waldron wrote:

I was thinking exactly this while I was reading Allen's post.

Would class method definitions use class.*? Seems like the wrong abstraction..? Maybe all functions and method definitions use function, while arrows use => (or whatever) to preserve correspondence to possible outer function?

the point here is that they are all "functions", regardless of how they are declared. When we write foo(), we don't care whether 'foo' is was declared using a function declaration, or a concise method, or class, or arrow syntax. We only care that it is a "function" which is an object that can be 'called' with an argument list. That is the exact sense that the word 'function' should be interpreted for those proposed meta properties.

I agree with you now and here's why:

function Component(target) { let a = function.arguments;

target.on("click", event => { // In here, arguments refers to the arguments object // that was created for this invocation of Component, // which makes sense because that object has no sense of // contextual qualification (something of a legacy problem).

function.arguments[0] === a[0]; // false

// ...because `function.arguments` here is for this arrow function.

}); }

# Brendan Eich (9 years ago)

Rick Waldron wrote:

function Component(target) { let a = function.arguments;

target.on("click", event => { // In here, arguments refers to the arguments object // that was created for this invocation of Component, // which makes sense because that object has no sense of // contextual qualification (something of a legacy problem). function.arguments[0] === a[0]; // false

// ...because `function.arguments` here is for this arrow function.

}); }

Joke's not funny if you have to explain it.

Seriously, I don't buy the explanation. I read the above and I see functionused twice. I expect the first use declares Component, and the second (even though in an arrow, because arrows uphold Tennent's Correspondence Principal with respect to this and arguments) to refer to the activation of the function declared by the first use of that f-keyword.

I agree with Mark.

# Andrea Giammarchi (9 years ago)

but how would you drop that listener, if that's even a concern of yours, beside the usage of function?

Does "I agree with Mark" means already two think arrows function should never be self-reference-able?

Just a genuine question,

# Brendan Eich (9 years ago)

Andrea Giammarchi wrote:

but how would you drop that listener, if that's even a concern of yours, beside the usage of function?

I'm not addressing your particular issue just yet -- patience!

Does "I agree with Mark" means already two think arrows function should never be self-reference-able?

No, again, I'm objecting to Allen's just-so story that function in an arrow refers to the arrow, and agreeing with Mark that the pellucid meaning (if there is one) would be the TCP one: the enclosing function around the arrow (if there is a function).

We need to get to the bottom of this to make progress, in any case. I don't think we should jump to =>.self for arrows and function.self

for functions, although that is an obvious "patch" to resolve the conflict. Patching to split forms and "do both" is often the wrong thing.

# Allen Wirfs-Brock (9 years ago)

On Feb 28, 2015, at 9:07 AM, Brendan Eich wrote:

No, again, I'm objecting to Allen's just-so story that function in an arrow refers to the arrow, and agreeing with Mark that the pellucid meaning (if there is one) would be the TCP one: the enclosing function around the arrow (if there is a function).

We need to get to the bottom of this to make progress, in any case. I don't think we should jump to =>.self for arrows and function.self for functions, although that is an obvious "patch" to resolve the conflict. Patching to split forms and "do both" is often the wrong thing.

If you want both a TCP-able from and a local (most closely enclosing callable thing) form then the later should also presumably also be applicable at the top level of functions.

The 'in' meta property prefix in combination with the 'function' prefix could do that job:

let foo=function () { function.count; //the number of actual arguments pass to current invocation of foo in.count; //same value as function.count () => { function.count; //the number of actual arguments pass to invocation of foo captured by this arrow in.count; //the numer of actual arguments passed to this invocation of this arrow } };

# Andrea Giammarchi (9 years ago)

FWIW in looks good to me, it's self explanatory , but in.self or in.current don't look god anymore. Would it be utterly insane to have in.function and function.function to reference to the function? If in.function works as function.function outside arrows, same as in.count reference to function.count outside arrows, then developers would probably always use the in.function version all the time and, when/if needed, have the ability to go function.function

I know latter sounds redundant, but it completes well with the in meta name I personally wouldn't mind.

# Leon Arnott (9 years ago)

On Sun, Mar 1, 2015 at 3:28 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>

wrote:

If you want both a TCP-able from and a local (most closely enclosing callable thing) form then the later should also presumably also be applicable at the top level of functions.

The 'in' meta property prefix in combination with the 'function' prefix could do that job:

One thing I feel about meta-properties is that they really should have some connection to the keyword's normal meaning, as is true of new.target. "in" currently exclusively refers to inherited property access, both as an operator and as a for-in keyword, and repurposing it to mean "invocation" when there's a meta-property attached is, well, not something I'd be proud of explaining. (Unless you took a leaf from del.icio.us and called it in.vocation.count :P)

# Rick Waldron (9 years ago)

On Sun, Mar 1, 2015 at 4:17 AM Leon Arnott <leonarnott at gmail.com> wrote:

On Sun, Mar 1, 2015 at 3:28 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:

If you want both a TCP-able from and a local (most closely enclosing callable thing) form then the later should also presumably also be applicable at the top level of functions.

The 'in' meta property prefix in combination with the 'function' prefix could do that job:

One thing I feel about meta-properties is that they really should have some connection to the keyword's normal meaning, as is true of new.target. "in" currently exclusively refers to inherited property access, both as an operator and as a for-in keyword, and repurposing it to mean "invocation" when there's a meta-property attached is, well, not something I'd be proud of explaining.

Strong agreement here. If in grows meta properties, they should by relevant to what the in operator does (which may mean none at all).

# Ben Newman (9 years ago)

How about function.sent, to evoke sending a value into the generator via .next?

# Allen Wirfs-Brock (9 years ago)

On Mar 2, 2015, at 9:22 AM, Rick Waldron wrote:

On Sun, Mar 1, 2015 at 4:17 AM Leon Arnott <leonarnott at gmail.com> wrote: On Sun, Mar 1, 2015 at 3:28 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote: If you want both a TCP-able from and a local (most closely enclosing callable thing) form then the later should also presumably also be applicable at the top level of functions.

The 'in' meta property prefix in combination with the 'function' prefix could do that job:

One thing I feel about meta-properties is that they really should have some connection to the keyword's normal meaning, as is true of new.target. "in" currently exclusively refers to inherited property access, both as an operator and as a for-in keyword, and repurposing it to mean "invocation" when there's a meta-property attached is, well, not something I'd be proud of explaining.

Strong agreement here. If in grows meta properties, they should by relevant to what the in operator does (which may mean none at all).

I'd agree, in an ideal world. But we have such a limited set of reserved words available that I'm not sure we can afford to be so choosy. In the end, the choice may be between meta property names that violate your proposed principle or not providing any way to access the corresponding value.

In my proposal, I choose "function" as a prefix because it was suggestive of function objects, rather than definitions that begin with keyword 'function'. For example, concise methods are more similar to 'function' functions than they are to arrow functions, but they aren't declared using the 'function' keyword.

I think that wanting to have both TCP-able form and an immediately enclosing form may be going a step too far in complexity. And it certainly puts an additional strain on the selection of the prefix keyword. If we;have to choose just one, I chose providing access to the immediately enclosing function object and its argument information over the TCP-able form. The reason is that within the non-TCP-able from form, local renames can be used to make outer meta properties accessible to inner functions. But if all you have is the TCPable form then these is no way for an arrow functions to access its own meta properties. And arguably, that is the key new functionality.

I still think that what I present in my proposal is a good balance both in terms of both naming and in terms of what new information is being made available to ES code