A new function name property proposal

# Brandon Benvie (13 years ago)

This is based on strawman:name_property_of_functions

Justification: the usefulness of the name of function is not just for debugging. It is useful in the same ways that property names as strings are such as dispatching by name or assigning by name.

The goals expand a bit beyond the ones in the strawman, and are also updated based on the current state of affairs. The first goal is that every function has an own "name" property, and this property is always a string (unless the user specifically decides to violate this norm), and that this name property is initialized with the value that makes sense from static semantics.The third goal is to allow predefined names to be altered in cases where it makes sense.

Semantics:

The baseline for every function is the 'name' property defined as { value: "", writable: true, enumerable: false, configurable: false }.

For FunctionDeclarations, named FunctionExpressions, MethodDefinitions, or accessor Properties then the function's "name" property is set to the given identifier. In the case of the constructor method of classes, the class name is used instead. In the case of accessors, 'get ' or 'set ' is included. The "name" property is set to non-writable. Function.prototype's name is also non-writable.

Anonymous FunctionExpressions and ArrowFunctionExpressions assigned in a VariableDeclaration or ObjectExpression are given the name of the variable or property they are assigned to and the name remains writable. Anonymous ClassExpressions follow the same semantics, with the name being used for the constructor method.

Whenever a function's name is defined by a Symbol instead of a regular identifier then the name is the result of ToString(symbol).

The name property should (probably) not have any reflection on the output of Function.prototype.toString.

# Brendan Eich (13 years ago)

Brandon Benvie wrote:

This is based on strawman:name_property_of_functions

Justification: the usefulness of the name of function is not just for debugging. It is useful in the same ways that property names as strings are such as dispatching by name or assigning by name.

The goals expand a bit beyond the ones in the strawman, and are also updated based on the current state of affairs. The first goal is that every function has an own "name" property, and this property is always a string (unless the user specifically decides to violate this norm), and that this name property is initialized with the value that makes sense from static semantics.The third goal is to allow predefined names to be altered in cases where it makes sense.

The third goal needs more discussion. The displayName property consulted by certain devtools (WebKit JS profiler, IIRC; others by now) was added to avoid non-writable .name. With downrev browsers in the field, how can we make name writable and let it be used cross-browser that way?

Semantics:

The baseline for every function is the 'name' property defined as { value: "", writable: true, enumerable: false, configurable: false }.

SpiderMonkey's .name property of functions is like this except for writable: false.

For FunctionDeclarations, named FunctionExpressions, MethodDefinitions, or accessor Properties then the function's "name" property is set to the given identifier.

Nit: don't define a baseline and then mutate it. Better to have the write immutable pd from the get-go, for each case.

In the case of the constructor method of classes, the class name is used instead. In the case of accessors, 'get ' or 'set ' is included.

at the front, to be super-clear ;-).

The "name" property is set to non-writable. Function.prototype's name is also non-writable.

Oh, I see now: you made .name writable only as a spec-internal thing. But wait, what about your goal 3?

Anonymous FunctionExpressions and ArrowFunctionExpressions assigned in a VariableDeclaration or ObjectExpression

"defined in an ObjectLiteral", rather.

are given the name of the variable or property they are assigned to and the name remains writable. Anonymous ClassExpressions follow the same semantics, with the name being used for the constructor method.

Really great stuff here, this makes me want to back your proposal. Just need to hash out the nits and points of confusion (possibly mine).

Whenever a function's name is defined by a Symbol instead of a regular identifier then the name is the result of ToString(symbol).

Symbols don't have useful ToString conversions, do they? Are you thinking of the optional string passed to the constructor, for diagnostics and debugging?

The name property should (probably) not have any reflection on the output of Function.prototype.toString.

You mean if f.name is writable then f.toString() should not reflect updates to f.name? Agreed, but why is f.name writable?

# Brendan Eich (13 years ago)

Brendan Eich wrote:

Nit: don't define a baseline and then mutate it. Better to have the write immutable pd from the get-go, for each case.

Wow, jetlag: "Better to have the right immutable pd", I meant.

# Axel Rauschmayer (13 years ago)

Whenever a function's name is defined by a Symbol instead of a regular identifier then the name is the result of ToString(symbol).

Symbols don't have useful ToString conversions, do they? Are you thinking of the optional string passed to the constructor, for diagnostics and debugging?

The name would be more useful if it could be either string or symbol. Not sure about security implications, though.

# Brandon Benvie (13 years ago)

The language I used was a bit confusing with to the baseline and what does what. In more direct, less spec-like language:

  • Function.prototype.name is frozen and set to the empty string.
  • named functions of any kind are also frozen and set to the name (how it currently works in browsers that support name)
  • class constructors maintain how they would work when desugared to a function, so represent the class for naming
  • In unnamed functions (arrow + anonymous), if there is a statically defined name that is appropriate to use then it is set as the name, but remains writable since the code author never explicitly set the name.

Another place where a name could be used is in assignment to member expressions where the property name is an identifier.

The following is all the places that should be covered and result in writable named functions:

var declFunc = function(){} var declArrow = () => {}

var declClass = class {}

var obj = { propFunc: function(){}, popArrow: () => {}, propClass: class {} }

object.memberFunc = function(){} object.memberArrow = () => {}

object.memberClass = class {}

# Brandon Benvie (13 years ago)

In to Symbols, yeah I was taking for granted them having a usable value coming ToString that originates from the argument to the constructor. I imagine that with syntactic support for Symbols this can mostly be automated by lifting the ToString representation from the Symbol's declaration.

# Aron Homberg (13 years ago)

I implemented a JS parser last week (in JS) which specially parses the function grammar. It also analyzes the function names based on the rules you described, Brandon. I came to the same results when thinking about how function names could be detected (statically).

But... there are some special cases where I wasn't able to find a good way to detect a function's name properly. In one case, thats because my parser just does a simple static parsing. Due to this, symbols are not evaluated by toString(), like mentioned. But that's not the end of the story, there are more pitfalls in practice...

A) Anonymous FunctionExpression's, stored in an array:

var someArray = [function() { // Have }, function() { // a }, function() { // lot of }, function() { // fun }];

e.g. Sencha's Ext JS does this in their Ext.data.Connection class where it's used to determine which ActiveXObject instance to choose for an XMLHttpRequest impl. in IE (calls the function in a loop)

I thought about combine sombol-name with array index, to give them a name. It would look like: "someArray-0", "someArray-1", etc. but somehow I don't really like that. Currently they are 'called': "anonymous-" + sequence++ - I increase this sequence with each anonymous function detected to give these functions a unique name (in script context).

B) FunctionExpression's assigned to a symbol:

var foo = { barFn: null };

foo[barFn] = function() { // whatever };

I faced this kind of code when parsing jQuery 1.8.1. It's hard to find a smart way here. The property name could be a function call too or whatever. So the name of the function is detected as "symbol-assigned-anonymous-" + sequence++ here. For sure, function name could be "foo[barFn]" too. Maybe, thats better for a developer in practice. With static analysis, these both solutions are all I can do here. But dynamic evaluation of the symbol and casting to a String, is too much for my static parsing algorithm.

Imagine stranger situations:

foo[fetchPropertyName()] = [function() { // no }, function() { // fun }];

Here a static function name detection fails too. A dynamic symbol to String conversion can be dangerous in such a situation too, right?

C) Scoped functions:

(function() { // what's my name? })

No chance, this one is totally anonymous, right? No matter if static or dynamic code analysis/parsing.


Now in practice: (parsing jQuery 1.8.1)

When I parse jQuery 1.8.1 using my parser, 511 functions get parsed and their names get detected correctly. 137 functions apply to one of the three special cases above. Most of them are symbol-assigned. Few are scoped by (). One additional function is being instantiated using "new Function('$code')". I didn't implemented a name detection for this grammar yet, so 138 of 511 functions are somehow "anonymous" after detecting function names using my static parsing algorithm.

I wonder what your thoughts are regarding these special cases and my decision to fallback to "symbol-assigned-anonymous-" + sequence++. Would you prefer using the sourcecode of the symbol assignment as detected function name name? It would be more descriptive in practice, right?

@Alex: "The name would be more useful if it could be either string or symbol" Please help me out :) The function will be assigned to the symbol, right? So using the symbol as name would simply be a reference to the function itself and equals to arguments.callee? Or did you mean the sourcecode of the symbol as the detected name of the function like I mentioned above?

Thanks and ,

  • Aron

2012/11/16 Axel Rauschmayer <axel at rauschma.de>

# John J Barton (13 years ago)

You might be interested in the work of Salman Mirghasemi on anonymous function naming in JavaScript: johnjbarton.github.com/nonymous/index.html

jjb

# Brandon Benvie (13 years ago)

Yeah, once you try to get fancy with interpolating a name you go down a dark path real quick. I think that tends to be more in line with the concept behind displayName which is the debug flavor of this and wants to do heroic feats to trace a usable debug name. The name property should be something that you'd actually purposefully write out yourself, not a derived object path. This is where the writability comes in. If the author does fail to hit the mark and doesn't provide a usable name, they can at least manually set it after the fact.

# Jorge Chamorro Bieling (13 years ago)

On 16/11/2012, at 21:46, Brandon Benvie wrote:

Yeah, once you try to get fancy with interpolating a name you go down a dark path real quick. I think that tends to be more in line with the concept behind displayName which is the debug flavor of this and wants to do heroic feats to trace a usable debug name. The name property should be something that you'd actually purposefully write out yourself, not a derived object path. This is where the writability comes in. If the author does fail to hit the mark and doesn't provide a usable name, they can at least manually set it after the fact.

Remember that a function's name is more than that string attached to function.name: it's also that var declared inside the function whose value is the function itself.

When you talk about writable and automatically generated names, do you mean both the string in function.name and that var's name?

# Axel Rauschmayer (13 years ago)

@Alex: "The name would be more useful if it could be either string or symbol" Please help me out :) The function will be assigned to the symbol, right? So using the symbol as name would simply be a reference to the function itself and equals to arguments.callee? Or did you mean the sourcecode of the symbol as the detected name of the function like I mentioned above?

Given that under ES6, the name of a method can be either a string or a symbol [1], I was wondering whether the latter possibility couldn’t be allowed when storing the method name in a property.

[1] www.2ality.com/2012/03/private-data.html

# Brandon Benvie (13 years ago)

The name property doesn't currently (and the I don't propose it should) have a correlation to the name in scope. In function declarations the name is only in scope because its declared in the outer scope, and this can be overwritten permanently rendering the name unusable in that scope. A named function expression puts the name association in a decorative scope that is untouchable and only accessible inside the function. In ES6 two new "function identifier modes" are introduced. For classes the same behavior as function declarations/expressions is used but extends the scope of the class name to all of class methods instead of just the constructor. For methods, there is no place where the function name is in scope (technically this existed for es5 accessors but its much more obvious/explicit for methods when their name throws a reference error).

So given all this, the name property should definitely continue to not be pinned to any scope record.

# Brandon Benvie (13 years ago)

Declarative scope...not decorative scope. Curses auto correct fail.

# Brendan Eich (13 years ago)

Brandon: thanks for reviving and revising my old strawman. I will edit your proposed changes in (and let you and the list know when I'm done so you can review) and present at the TC39 meeting in the last week of November. Thanks again, great work!

# Brandon Benvie (13 years ago)

Excellent! I must admit to having a pretty ridiculous obsession with the name property of functions in particular, so I would be much delighted to see improvements and standardization come to it.

# Yehuda Katz (13 years ago)

This post is about my experience with the lookup-by-reference and debug use-cases for Function#name. Both use-cases are very general-purpose--my examples from Ember.js are just representative examples, and illustrate ways that we have worked around existing limitations to provide missing functionality.

String References * * Because of the difficulty in managing load order in current JavaScript, as well as a desire to allow for clean dependency injection, we allow many cross-object associations do be defined using Strings. In general, these strings are evaluated the first time the associated object is used at runtime, which allows dependencies to be injected and ensures that all modules to be loaded before references are evaluated.

Here is an example of associations described in Ember Data:

App.Person = DS.Model.extend({ comments: hasMany('App.Comment') });

// in another module

App.Comment = DS.Model.extend({ person: belongsTo('App.Person') });

So how does this sort of thing work? Instead of making App a standard JavaScript object, App is an instance of Ember.Namespace. Once we know its name (which we do by searching on window for instances of Ember.Namespace, gross, I know), we can easily resolve String names into actual objects at runtime.

This solution, of course, assumes coordination across a global object, which isn't desirable in a world with modules, and the problem may even be fully mitigated in a world with modules. I'm not sure how well modules handle circular dependencies--lazily evaluating strings handles the problem elegantly by deferring evaluation of dependencies until all of the modules have loaded.

Sencha uses a similar approach for dependencies (see www.sencha.com/learn/how-to-use-classes-in-sencha-touch-2). In particular, Sencha defines and references classes by Strings, avoiding the reference problem. This approach requires the use of a static creation function (Ext.create('Animal', { })), so the String semantics leak into runtime as well.

Internally, Objective-J compiles class references to a lookup in REGISTERED_CLASSES, which serves a similar purpose, but allows for nicer syntax through a preprocessor.

This use-case would not be addressed by improved lexical inference of names in functions and classes, but the final module proposal will hopefully moot this use-case. There are probably other lookup-by-reference use-cases that would not be handled by modules.

Debugging * * Similarly, Ember provides a default toString that is more descriptive than the default [object Object].

App = Ember.Namespace.create(); App.Person = Ember.Object.extend(); App.Person.toString(); // "App.Person" var person = new App.Person(); person.toString() // "App.Person:ember1234"

The part after the colon is a debug-friendly object ID we lazily create when needed. (also, until we have a reliable Set, Map and WeakMap, that object ID is also used as the key in Objects that are used to emulate Sets, Maps and WeakMaps).

Historically, we have tried to install these toString values as displayName. Because Chrome does not support displayName, we eventually stopped trying to add it. (also, our current lookup implement is lazy, like toString, and displayName is an eager value).

For what it's worth, Chrome's attempt to guess names in lieu of support for displayName, while better than nothing, isn't good enough in many cases and blocks us from providing the best possible debugging experience in the Chrome debugger. Many others have been similarly stymied, the Chrome ticket to support displayName ( code.google.com/p/chromium/issues/detail?id=17356) has been open since 2009 and has comments as recently as this year.

For this use-case, Maciej or Dave's proposal at strawman:name_property_of_functions would be helpful. I like Dave's variant (which allows specification of separate call behavior, construct behavior and an alternative prototype to Function.prototype). This would allow a very simple implementation of imperative class-side inheritance, among other things. I know this can be achieved via proxies and/or proto, but this is much nicer.

In general, I like the idea of inferring useful information statically. The one caveat is that libraries creating class-like abstractions usually create constructors inside of the implementation. In Ember's case (see jsbin.com/ijicor/78), this means that the statically inferred name is always Class. Interestingly (and usefully), Firefox uses the provided toString value in its output.

In a similar Backbone example (see jsbin.com/uqanem/1), Chrome infers d, and prints d plus a set of internal attributes. Firefox just prints the internal attributes.

Of course, in the long run, many of these non-transpiled use cases would be handled by a robust and broadly implemented declarative class syntax. Transpiled use cases (like the original case, Objective-J) would probably continue to benefit from more control over the name.

TL;DR * * I would really like to see Dave's Function.create(name, call, construct, proto) proposal come to pass. Fleshing out static name extraction as described above would be a big benefit to a lot of common uses, and I am in favor of it. Direct control of the name, not static inference, is needed for imperative class-like abstractions.

# Jorge Chamorro Bieling (13 years ago)

On 17/11/2012, at 18:45, Brandon Benvie wrote:

The name property doesn't currently (and the I don't propose it should) have a correlation to the name in scope. In function declarations the name is only in scope because its declared in the outer scope, and this can be overwritten permanently rendering the name unusable in that scope. A named function expression

--and function declarations too--

puts the name association in a decorative scope that is untouchable and only accessible inside the function.

It's not clear to me whether one might end with function whose name (the value returned by function.name) might be !== than its name as "seen" from inside the function itself:

function ƒ () { return (ƒ.name !== 'ƒ') }

?

# Brandon Benvie (13 years ago)

function x(){ x = { name: 'y' }; return x.name } x(); // 'y'

(function x(){ x = { name: 'y' }; return x.name })() // 'x'

# Jorge Chamorro (13 years ago)

On 19/11/2012, at 20:34, Brandon Benvie wrote:

On Mon, Nov 19, 2012 at 2:29 PM, Jorge Chamorro Bieling <jorge at jorgechamorro.com> wrote:

On 17/11/2012, at 18:45, Brandon Benvie wrote:

The name property doesn't currently (and the I don't propose it should) have a correlation to the name in scope. In function declarations the name is only in scope because its declared in the outer scope, and this can be overwritten permanently rendering the name unusable in that scope. A named function expression

--and function declarations too--

puts the name association in a decorative scope that is untouchable and only accessible inside the function.

It's not clear to me whether one might end with function whose name (the value returned by function.name) might be !== than its name as "seen" from inside the function itself:

function ƒ () { return (ƒ.name !== 'ƒ') }

?

function x(){ x = { name: 'y' }; return x.name } x(); // 'y'

(function x(){ x = { name: 'y' }; return x.name })() // 'x'

The behaviour of the function declaration surprises me for since the days of the discussions about the ditching of arguments.callee, I seem to recall, one of the arguments in favor of ditching it was that a reference to itself was already available there, inside the named function, safe and in scope, ever, and not only in the case of (named) function expressions.

Having it declared (only) in the outer scope has risks that arguments.callee didn't have, and that NFEs don't have. Is there any justification for this difference?

# Brandon Benvie (13 years ago)

I don't know the specific reasoning behind it. I guess the idea is that a function is declared in a maximum of one scope. For the declaration it's the outer scope, for a named function expression it's a static scope that sits between the outer scope and the (during execution of the function) inner scope.

Also just to clarify, the above isn't something I'm proposing. It's how things currently work.

# Brendan Eich (13 years ago)

Brandon Benvie wrote:

I don't know the specific reasoning behind it. I guess the idea is that a function is declared in a maximum of one scope. For the declaration it's the outer scope, for a named function expression it's a static scope that sits between the outer scope and the (during execution of the function) inner scope.

Also just to clarify, the above isn't something I'm proposing. It's how things currently work.

Right. I think Jorge may be concerned that naming a function does not always relieve the "need" for arguments.callee. But that's only true in a function declaration, which is inherently named, as you showed -- and only if one then overwrites the name in its scope.

So don't do that. Fear that someone else might means you are in the global scope, which means that instead of using such a hard case to justify arguments.callee, you ought to modularize with an IIFE or (in due course) ES6 module.

# Jorge Chamorro (13 years ago)

On 22/11/2012, at 09:38, Brendan Eich wrote:

Brandon Benvie wrote:

I don't know the specific reasoning behind it. I guess the idea is that a function is declared in a maximum of one scope. For the declaration it's the outer scope, for a named function expression it's a static scope that sits between the outer scope and the (during execution of the function) inner scope.

Also just to clarify, the above isn't something I'm proposing. It's how things currently work.

Right. I think Jorge may be concerned that naming a function does not always relieve the "need" for arguments.callee. But that's only true in a function declaration, which is inherently named, as you showed -- and only if one then overwrites the name in its scope.

So don't do that. Fear that someone else might means you are in the global scope, which means that instead of using such a hard case to justify arguments.callee, you ought to modularize with an IIFE or (in due course) ES6 module.

To clarify, I wasn't trying to justify arguments.callee.

"don't do that" is a solution, for this and for many other WTFs and footguns...

But, isn't the NFEs' way the Right Way to do it?

Do we want this footgun in function declarations?

Why?

Is there any reason for not removing it? (Other than "because it's a corner case"?)

# Brandon Benvie (13 years ago)

In ES6 methods (both in classes and in object literals) don't create any binding at all for their name. Would you say that's better or worse?

As far as changing the binding behavior of names for existing function declaration and expression forms...it'd be fiddling with something that has (I think) always been part of JS and is a core mechanic and would have a widely felt impact if changed. It's just not possible to change it even if it was desired.

# Brendan Eich (13 years ago)

Jorge Chamorro wrote:

On 22/11/2012, at 09:38, Brendan Eich wrote:

Brandon Benvie wrote:

I don't know the specific reasoning behind it. I guess the idea is that a function is declared in a maximum of one scope. For the declaration it's the outer scope, for a named function expression it's a static scope that sits between the outer scope and the (during execution of the function) inner scope.

Also just to clarify, the above isn't something I'm proposing. It's how things currently work. Right. I think Jorge may be concerned that naming a function does not always relieve the "need" for arguments.callee. But that's only true in a function declaration, which is inherently named, as you showed -- and only if one then overwrites the name in its scope.

So don't do that. Fear that someone else might means you are in the global scope, which means that instead of using such a hard case to justify arguments.callee, you ought to modularize with an IIFE or (in due course) ES6 module.

To clarify, I wasn't trying to justify arguments.callee.

"don't do that" is a solution, for this and for many other WTFs and footguns...

But, isn't the NFEs' way the Right Way to do it?

Do what?

Function declarations are useful too. They hoist so you can write them in top-down order and call in any order from top-level code. You can't do this with vars initialized with function expressions.

Do we want this footgun in function declarations?

What footgun? People don't overwrite function declarations' bindings by accident much, if at all. I can't remember hearing of this lately, although it can happen when loading libraries where a common name is used by two libraries.

Programmers do intentionally replace a function's name in its scope, e.g. to auto-memoize.

Why?

Is there any reason for not removing it? (Other than "because it's a corner case"?)

Removing what? The writable binding created by a function declaration? That's required by backward compatibility (e.g. the memoization pattern).

# Jorge Chamorro (13 years ago)

On 23/11/2012, at 18:47, Brendan Eich wrote:

Jorge Chamorro wrote:

On 22/11/2012, at 09:38, Brendan Eich wrote:

Right. I think Jorge may be concerned that naming a function does not always relieve the "need" for arguments.callee. But that's only true in a function declaration, which is inherently named, as you showed -- and only if one then overwrites the name in its scope.

So don't do that. Fear that someone else might means you are in the global scope, which means that instead of using such a hard case to justify arguments.callee, you ought to modularize with an IIFE or (in due course) ES6 module.

To clarify, I wasn't trying to justify arguments.callee.

"don't do that" is a solution, for this and for many other WTFs and footguns...

But, isn't the NFEs' way the Right Way to do it?

Do what?

Bind the name inside the function too.

Function declarations are useful too. They hoist so you can write them in top-down order and call in any order from top-level code.

And hoisting is handy, I use it a lot and can't live without it.

You can't do this with vars initialized with function expressions.

Of course, if they were interchangeable we'd simply write var x= function x () {}; and done.

Do we want this footgun in function declarations?

What footgun?

The footgun (1) is to have the name bound only in the outer scope.

People don't overwrite function declarations' bindings by accident much, if at all. I can't remember hearing of this lately, although it can happen when loading libraries where a common name is used by two libraries.

Yes it's a corner case.

Programmers do intentionally replace a function's name in its scope, e.g. to auto-memoize.

Oh, how does that work? I've written memoizers but never needed to overwrite a name.

Why?

Is there any reason for not removing it? (Other than "because it's a corner case"?)

Removing what?

The footgun (1)

The writable binding created by a function declaration? That's required by backward compatibility (e.g. the memoization pattern).

The -outer- writable binding isn't the problem, the problem is the lack of binding in the inner scope. Is there a reason for not having it?

# Brendan Eich (13 years ago)

Jorge Chamorro wrote:

On 23/11/2012, at 18:47, Brendan Eich wrote:

Jorge Chamorro wrote:

On 22/11/2012, at 09:38, Brendan Eich wrote:

Right. I think Jorge may be concerned that naming a function does not always relieve the "need" for arguments.callee. But that's only true in a function declaration, which is inherently named, as you showed -- and only if one then overwrites the name in its scope.

So don't do that. Fear that someone else might means you are in the global scope, which means that instead of using such a hard case to justify arguments.callee, you ought to modularize with an IIFE or (in due course) ES6 module. To clarify, I wasn't trying to justify arguments.callee.

"don't do that" is a solution, for this and for many other WTFs and footguns...

But, isn't the NFEs' way the Right Way to do it? Do what?

Bind the name inside the function too.

That's not a compatible change, and unmotivated by any actual foot damage.

Do we want this footgun in function declarations? What footgun?

The footgun (1) is to have the name bound only in the outer scope.

We need evidence this is a real hazard. Otherwise you're assuming a conclusion and using a circular argument of sorts: that lack of the inner unwritable name binding is a problem requiring just that solution.

People don't overwrite function declarations' bindings by accident much, if at all. I can't remember hearing of this lately, although it can happen when loading libraries where a common name is used by two libraries.

Yes it's a corner case.

Ok, so what's the non-corner foot-damaging case?

Programmers do intentionally replace a function's name in its scope, e.g. to auto-memoize.

Oh, how does that work? I've written memoizers but never needed to overwrite a name.

osteele.com/posts/2006/04/one-line-javascript-memoization

Works on global functions as well prototype methods.

The writable binding created by a function declaration? That's required by backward compatibility (e.g. the memoization pattern).

The -outer- writable binding isn't the problem, the problem is the lack of binding in the inner scope. Is there a reason for not having it?

Again, introducing such a binding is an incompatible change. I don't know what it might break, but I doubt anyone wants the risk. Also there's overhead in making such an inner binding -- another reason implementors won't go there. Finally, you have not justified this change by any evidence it addresses a real, observed hazard.

# Jorge Chamorro (13 years ago)

On 24/11/2012, at 07:14, Brendan Eich wrote:

Jorge Chamorro wrote:

Bind the name inside the function too.

That's not a compatible change, and unmotivated by any actual foot damage.

The footgun (1) is to have the name bound only in the outer scope.

We need evidence this is a real hazard. Otherwise you're assuming a conclusion and using a circular argument of sorts: that lack of the inner unwritable name binding is a problem requiring just that solution.

Yes it's a corner case.

Ok, so what's the non-corner foot-damaging case?

Programmers do intentionally replace a function's name in its scope, e.g. to auto-memoize.

Oh, how does that work? I've written memoizers but never needed to overwrite a name.

osteele.com/posts/2006/04/one-line-javascript-memoization

Works on global functions as well prototype methods.

It can be done with FDs, but all the examples are using NFEs.

The writable binding created by a function declaration? That's required by backward compatibility (e.g. the memoization pattern).

The -outer- writable binding isn't the problem, the problem is the lack of binding in the inner scope. Is there a reason for not having it?

Again, introducing such a binding is an incompatible change. I don't know what it might break, but I doubt anyone wants the risk. Also there's overhead in making such an inner binding -- another reason implementors won't go there. Finally, you have not justified this change by any evidence it addresses a real, observed hazard.

Sorry, but I can't help thinking that fib should be bound in FDs as in NFEs:

function fib (n) { return (n < 2) ? 1 : fib(n-2)+ fib(n-1); }

because if not it becomes a free var meaning that any recursive FD can be broken from the outside at any time, which does not seem to be the Right Way to do the things.

Sounds like a WTF... one that's rarely going to bit, but a WTF nevertheless.

Don't you think so?

# Brendan Eich (13 years ago)

Jorge Chamorro wrote:

On 24/11/2012, at 07:14, Brendan Eich wrote:

Programmers do intentionally replace a function's name in its scope, e.g. to auto-memoize. Oh, how does that work? I've written memoizers but never needed to overwrite a name. osteele.com/posts/2006/04/one-line-javascript-memoization

Works on global functions as well prototype methods.

It can be done with FDs, but all the examples are using NFEs.

Yes. So? The point is we can't make an incompatible change without more motivation and some sense that we're not going to break the web. Neither is in evidence.

Don't you think so?

No. You're rehashing a hypothetical worry at this point. Evidence first, to get any farther.

# Jorge Chamorro (13 years ago)

On 25/11/2012, at 00:52, Brendan Eich wrote:

No. You're rehashing a hypothetical worry at this point.

No worries, but it's not a hypothesis that code outside a recursive FD can break it at its will.

Evidence first, to get any farther.

The only evidence is that sometimes yes sometimes no, functions' names are free vars.

# Brendan Eich (13 years ago)

Updating this thread. I need to update the wiki still, but at last week's TC39 meeting we did agree to infer name mostly as you proposed. The one change of note is to make f.name writable always.

BTW, I just noticed that SpiderMonkey infers a "display id" now, along the lines of your proposal: bugzilla.mozilla.org/show_bug.cgi?id=433529. No in-language reflection other than Error.stack, but there's a JS API.

If you could check out the SpiderMonkey patch that landed, I'd appreciate it.