name property for built-in functions??
There is long-standing precedent for the plain identifier:
js> Array.prototype.toString.name
toString
What should (new Function).name or (equivalently) Function().name
return? Precedent in some engines:
js> (new Function).name
anonymous
An anonymous function expression returns the empty string in some
implementations:
js> (function(){}).name
js> typeof (function(){}).name
string js> (function(){}).name.length
0
/be
(Is "printString" a VB-ism? ;-)
Brendan Eich wrote:
(Is "printString" a VB-ism? ;-)
Oops... It's a Smalltalk
From: Brendan Eich [mailto:brendan at mozilla.com]
What should (new Function).name or (equivalently) Function().name return? Precedent in some engines:
js> (new Function).name anonymous
An anonymous function expression returns the empty string in some implementations:
js> (function(){}).name
js> typeof (function(){}).name string js> (function(){}).name.length 0
I have a hard time buying (new Function).name === "anonymous" when (function(){}).name==="". I think it is fine to have the name distinguish functions created using new Function from functions created via function expressions that don't have an explicit name. However, the concept of "anonymous" could reasonably be applied to either so using it for only one of them is likely to create confusion for programmer to don't deeply understand this difference. Plus, "anonymous" could actually be the declared name of a function.
In addition, at the Mt. View meeting we decide that if the target function of a bind call has the empty string as its name then the name of the function that is return from the bind is "bind anonymous function". That would add to the confusion.
While it may go against precedent I think it would be more useful if (new Function).name === "new Function". I can live with (function(){}).name==="" although (function(){}).name==="anonymous function" would probably be better.
On Mar 1, 2009, at 10:28 AM, Allen Wirfs-Brock wrote:
From: Brendan Eich [mailto:brendan at mozilla.com]
What should (new Function).name or (equivalently) Function().name
return? Precedent in some engines:js> (new Function).name anonymous
An anonymous function expression returns the empty string in some
implementations:js> (function(){}).name
js> typeof (function(){}).name string js> (function(){}).name.length 0
I have a hard time buying (new Function).name === "anonymous" when
(function(){}).name==="".
Me too, FWIW. I don't think this Function-constructor case is as
important as the anonymous function expression one.
While it may go against precedent I think it would be more useful if
(new Function).name === "new Function".
That's better than "anonymous". I'm not so sure it's better than "" or
undefined, based on use-case arguments below.
I can live with (function(){}).name==="" although (function() {}).name==="anonymous function" would probably be better.
If the use-case is diagnostics of the form "unexpected argument to " +
funarg.name, then you're right. If the use-case is forking control
flow based on anonymous vs. named function expression (or definition)
then "" or even undefined is better.
Without more evidence, I would be in favor of a concise "no name"
value, and since at least some implementations (Rhino, SpiderMonkey --
not sure about IE, can't test at home) use "", "" beats undefined by
that criterion.
Using undefined as the "no name" value happens to match ES3 results
for any function's name property, but that does not seem helpful for
cross-browser scripts. Any new use of the name property might want to
be conditional (a la "object detection"), even for anonymous functions.
It's hard to be sure without more user feedback, though.
Unless others speak up, the path of least resistance is to use "" for both unnamed function expressions and new Function as that language is already in the ES3.1 spec.
Allen Wirfs-Brock wrote:
Unless others speak up, the path of least resistance is to use "" for both unnamed function expressions and new Function as that language is already in the ES3.1 spec.
Bully!
Personally, I always name my function expressions, (and don't use new
Function) so I am not presented with this dilemma. And that works
great for me except for the one runtime in the universe that makes a
hash of named function experssions...
For introspection purposes, I create an object identity table and
assign unique identifiers to objects, so I'd find either undefined or
"" acceptable for unnamed functions.
On Mar 1, 2009, at 10:28 AM, Allen Wirfs-Brock wrote:
From: Brendan Eich [mailto:brendan at mozilla.com]
What should (new Function).name or (equivalently) Function().name
return? Precedent in some engines:js> (new Function).name anonymous
An anonymous function expression returns the empty string in some
implementations:js> (function(){}).name
js> typeof (function(){}).name string js> (function(){}).name.length 0
I have a hard time buying (new Function).name === "anonymous" when
(function(){}).name==="". I think it is fine to have the name
distinguish functions created using new Function from functions
created via function expressions that don't have an explicit name.
However, the concept of "anonymous" could reasonably be applied to
either so using it for only one of them is likely to create
confusion for programmer to don't deeply understand this difference.
Plus, "anonymous" could actually be the declared name of a function.In addition, at the Mt. View meeting we decide that if the target
function of a bind call has the empty string as its name then the
name of the function that is return from the bind is "bind anonymous
function". That would add to the confusion.While it may go against precedent I think it would be more useful if
(new Function).name === "new Function". I can live with (function() {}).name==="" although (function(){}).name==="anonymous function"
would probably be better.
Surprising though it may be, it seems that (new Function).name ===
"anonymous" may be relevant to Web compatibility. We changed
JavaScriptCore to match SpiderMonkey on this as a result of this bug:
bugzilla.opendarwin.org/show_bug.cgi?id=7726
While it's true that the code relying on the name may be completely
bogus, or that the specific string "anonymous" may only matter in the
Function.prototype.toString serialization and not in the name
property, I think the potential improvement is not great enough to be
worth the risk.
Note: this was not what I expected to find when I went spelunking in
our bug database; I thought we just blindly followed Gecko here before
I did the research.
I strongly suspect code also depends on (function(){}).name==="" but I
don't have a clear-cut example handy.
, Maciej
, Maciej
On Mar 3, 2009, at 2:39 PM, Maciej Stachowiak wrote:
Surprising though it may be, it seems that (new Function).name ===
"anonymous" may be relevant to Web compatibility. We changed
JavaScriptCore to match SpiderMonkey on this as a result of this bug:
I can't reach that hostname, but bugs.webkit.org/show_bug.cgi?id=7726 works.
BTW, the ability to write a program whose entire source is "function
() {}" is an old, pre-ES3 feature of SpiderMonkey that people still
depend on, especially when using eval (not new Function) to generate a
lambda from source.
Per ES3 this should be a syntax error as Darin Adler pointed out in
the bugs.webkit.org bug, but we have had to keep compatibility with
what came before ES3 on this point. There's an API option
(JSOPTION_ANONFUNFIX) to make this case an error per spec.
I strongly suspect code also depends on (function(){}).name==="" but
I don't have a clear-cut example handy.
I voiced the same suspicion. I didn't know any web site depending on
Function().name == "anonymous", though. What a world!
Strictly speaking, this issue seems to be more about Function.prototype.toString than it is about Function.prototype.name.
Here is what each of the 5 browsers in our regular test set does for each when called on a (new Function):
(new Function).toString ==> "function anonymous() { }" assorted whitespace/new line variations FF(3.0.6), Safari(3.1.2), Chrome(1.0) , IE (7):
(new Function).toString ==> "function (){}" (with various new lines inserted) Opera(9.63)
(function() {}).toString() ==> "function (){}" (with various new lines inserted) FF, Safari, Chrome, Opera
(function() {}).toString() ==> "(function (){})" (note the outer parens) IE
(new Function).hasOwnProperty("name") ==> true (new Function).name ==> "anonymous" (function() {}).name ==> ""
FF, Chrome
(new Function).hasOwnProperty("name") ==> false
Opera, Safari, IE
Function.prototype.hasOwnProperty("name") ==> true
Function.prototype.name ==> "" FF
Function.prototype.hasOwnProperty("name") ==> true
Function.prototype.name ==> "Empty" Chrome
Function.prototype.hasOwnProperty("name") ==> false Safari, Opera, IE
ES3 says that Function.prototype.toString produces a string that has the syntax of a FunctionDeclaration and FunctionDeclaration must have an identifier in the function name position. All the implementation except for Opera comply and agree upon the name "anonymous" for anonymous functions created with (new Function). This is a case where Opera is out of conformance with ES3 by generating what looks like a function expression rather than a function declaration. However, all of the browsers are out of conformance with ES3 for toString for anonymous functions created using a FunctionExpression. IE throws in an extra set of parens in that case.
The Es3 extension of a name property for functions only appear to be implemented by FF and Chrome, and they disagree about the name of Function.prototype.
The ES specification of Function.prototype.toString clearly does not reflect reality. The goal is to achieve uniformity among implementations while minimizing impact upon existing code. Given this, I propose that we modify the first paragraph of 15.2.4.2 (Function.prototype.toString) with the
An implementation-dependent >>>string<<< representation of the function is returned. This representation has the syntax of a >>>FunctionExpression<<<. Note in particular that the use and placement of white space, line terminators, and semicolons within the representation string is implementation-dependent. >>>If the function was created by evaluating a FunctionDeclaration then the returned representation must include the identifier from the FunctionDeclaration in the optional identifier position in the FunctionExpression. If the function was created by a call to the standard built-in Function constructor then the name "anonymous" must occur in the optional identifier position of the returned string. If the function was created by evaluating a FunctionExpression that did not include an identifier, by a get or set property assignment in an ObjectLiteral, or by a call to the Function.prototype.bind built-in method then no identifier is included in the returned representation. If the function is a built-in function then the property name assigned to the function in this specification (or by the implementation if it is a non-standard function) is included in as the identifier in the returned representation. If the function is a host object then whether or not an identifier is present is implementation defined.<<<
(maybe I can work on the wording ;-)
The above codifies what currently is most commonly implemented with some elaboration for new features in ES3.1 and should take care of the actual use case that Maciej identifier in the bug report.
Regarding, Function.prototype.name, it doesn't appear to be nearly so universally implemented. Given that, I suggest we use the opportunity of defining it in ES3.1 to maximize its utility by providing more descriptive names than what is current generated by Function.prototype.toString. I'd prefer that we stick with what is in current ES3.1 draft which is: Defined by name FunctionDeclaration the identifier from the declaration FunctionExpression with name the identifier from the function expression FunctionExpresion w/o name the empty string Object literal get/set "get <property name>" or "set <property name>"
Bound function "bind <target function name>" or " bind anonymous function" (new Function) "new Function"* Built-in specified name
*the current draft says "" but I consider this to be a bug. I apparently lost this change when Word crashed on me Sunday :-(
A quick post-script. We could also give Function.prototype.name a different name, perhaps "identifier" if we don't want to trample over the existing FF and Chrome implementations. Too bad "name" is such a good name for this functionality.
I like most of what you just proposed, except that I find it surprising that a function's ".name" is not the identifier used by ".toString()" on that function. This same issue just came up on an internal list at Google: Objecting that since ES3.1 specs that the ".name" for bound functions and literal getters and setters is not an identifier, it would break .toString() if it were used in the identifier position of a function's .toString().
On Tue, Mar 3, 2009 at 7:35 PM, Allen Wirfs-Brock < Allen.Wirfs-Brock at microsoft.com> wrote:
A quick post-script. We could also give Function.prototype.namefunction.prototype.namea different name, perhaps "identifier" if we don't want to trample over the existing FF and Chrome implementations. Too bad "name" is such a good name for this functionality.
The other way to reconcile this is to retreat to keeping the name "name", but having it always agree with the identifier used the function's .toString(). If we do this, then we should choose a good enough identifier mangling scheme for bound functions ("bind_<original-ident>") and literal
getters and setters ("get_<ident>", "set_<ident>"), and use it in both the .name and in the identifier position of .toString(). Ugly as this is, I think it's better than having two different names associated with the same function by two different parts of our API merely because we couldn't agree on one.
Pave the cowpaths. Don't be inventin' at this late date. Nuff said.
I'm not sure that there ever was a stated requirement that Function.prototype.name yield the same value that appears in the identifier position of a Function declaration/expression text produced by toString. If that was to be the case, then name offers very little added value as the identifier can be extracted from from the toString value with a fairly simple RegExp. It always seemed to me that the real utility of the proposed name property was to provide additional descriptive information about functions that might be useful for debugger. The underscored prefix does provide this except for the obvious ambiguities with functions explicitly named in that manner. We did discuss this at the MV meeting in the context of name bind functions and object literal get/set functions and nobody seems concerned about the space in those names.
If we really want to establish a Function.prototype.name/Function.prototype.toString invariant then we need to also worry about what happens if Function.prototype.name is modified (it's [[Writable]]:true) and in particular if its value is set to a non-string. Do you want toString to specify that it just uses ToString() applied to the value of the name property?
Last fall, we dropped Function.prototype.arguments because of unresolved issues that were no more complex then these. Are we getting to the same point here?
Finally, I think the really important issue from an interoperability perspective is the toString issues that Maciej pointed out. Regardless of what we do with the name property I think we need to better specify it for consistent interoperability and compatibility with the existing web. I think the proposal for toString in my earlier message addresses those concerns.
Allen
From: Mark S. Miller [mailto:erights at google.com] Sent: Tuesday, March 03, 2009 8:02 PM To: Allen Wirfs-Brock Cc: Brendan Eich; Maciej Stachowiak; es-discuss at mozilla.org Subject: Re: name property for built-in functions??
I like most of what you just proposed, except that I find it surprising that a function's ".name" is not the identifier used by ".toString()" on that function. This same issue just came up on an internal list at Google: Objecting that since ES3.1 specs that the ".name" for bound functions and literal getters and setters is not an identifier, it would break .toString() if it were used in the identifier position of a function's .toString().
On Tue, Mar 3, 2009 at 7:35 PM, Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com<mailto:Allen.Wirfs-Brock at microsoft.com>> wrote:
A quick post-script. We could also give Function.prototype.namefunction.prototype.name a different name, perhaps "identifier" if we don't want to trample over the existing FF and Chrome implementations. Too bad "name" is such a good name for this functionality.
The other way to reconcile this is to retreat to keeping the name "name", but having it always agree with the identifier used the function's .toString(). If we do this, then we should choose a good enough identifier mangling scheme for bound functions ("bind_<original-ident>") and literal getters and setters ("get_<ident>", "set_<ident>"), and use it in both the .name and in the identifier position of .toString(). Ugly as this is, I think it's better than having two different names associated with the same function by two different parts of our API merely because we couldn't agree on one.
On Mar 4, 2009, at 9:49 AM, Allen Wirfs-Brock wrote:
I’m not sure that there ever was a stated requirement that
Function.prototype.name yield the same value that appears in the
identifier position of a Function declaration/expression text
produced by toString. If that was to be the case, then name offers
very little added value as the identifier can be extracted from
from the toString value with a fairly simple RegExp.
Historical note: name in SpiderMonkey and the Netscape progenitor
predate ES3 and RegExps (RegExps based on Perl 4 were coming along
before ES3 standardized Perl-5-ish RegExps).
Fairly simple regexps can do a great many things, as David-Sarah
pointed out re: parseInt weakness. That's no reason for varying name
from its obvious connotation if the primary use-case is getting the
same name that follows 'function' in the toString result.
It always seemed to me that the real utility of the proposed name
property was to provide additional descriptive information about
functions that might be useful for debugger. The underscored prefix
does provide this except for the obvious ambiguities with functions
explicitly named in that manner. We did discuss this at the MV
meeting in the context of name bind functions and object literal get/ set functions and nobody seems concerned about the space in those
names.
It's a roll of the dice; I recall saying we would have to implement
and see how it went.
Use-case analysis needs user testing. If you think the use-case is a
diagnostic informative identifying string to be formatted into a
localized sentence, multiple words separate by spaces are problematic
for l10n and ambiguity reasons.
It seems to me we should not be making stuff up here that has not
already been implemented. If we must, we could try to get feedback
from prototype 3.1 implementations. We can't afford to do too much of
this late innovation, though, because we won't be able to get
sufficient user testing for very much novelty, in the time alloted.
If we really want to establish a Function.prototype.name/ Function.prototype.toString invariant then we need to also worry
about what happens if Function.prototype.name is modified (it’s
[[Writable]]:true) and in particular if its value is set to a non- string. Do you want toString to specify that it just uses
ToString() applied to the value of the name property?
Why in the world is name writable?
js> function f(){}
js> f.name
f js> f.name = 'g'
g js> f.name
f
It's not in Mozilla's implementations. AFAIK there's no precedent
elsewhere that has name predefined yet writable.
Last fall, we dropped Function.prototype.arguments because of
unresolved issues that were no more complex then these. Are we
getting to the same point here?
I'm fine with dropping the Function name property from 3.1. We should
develop a Harmony proposal that can be prototyped and tested at
greater leisure if we drop it, not just drop it and ignore the
progress made so far on this point.
Finally, I think the really important issue from an interoperability
perspective is the toString issues that Maciej pointed out.
Regardless of what we do with the name property I think we need to
better specify it for consistent interoperability and compatibility
with the existing web. I think the proposal for toString in my
earlier message addresses those concerns.
It would be bad to overspecify, e.g. whitespace or comment
preservation, or particular formatting. Existing code copes with
various implementation artifacts. What is not good is the failure to
produce anything compilable for a scripted function, or something that
miscompiles to a function not isomorphic to the original.
From: Brendan Eich [mailto:brendan at mozilla.com]<mailto:[mailto:brendan at mozilla.com]>
Why in the world is name writable?
Default ES3.1 policy for new properties that are added to the spec. is to make them writable in case there is existing code that coincidentally uses that property name for other purposes. If this isn't a concern for Function.prototype.name (and Mozilla's use of it suggests that this is probably safe) then it could be specified as non-writable.
I'm fine with dropping the Function name property from 3.1
I think that might be best, although we would still need to define the toString name for all possible function creation scenarios.
It would be bad to overspecify,
Agreed. It's only the name that I think we need to further specify toString. I'm fine with the current formatting variations.
From: Brendan Eich [mailto:brendan at mozilla.com] Sent: Wednesday, March 04, 2009 1:17 PM To: Allen Wirfs-Brock Cc: Mark S. Miller; Maciej Stachowiak; es-discuss at mozilla.org Subject: Re: name property for built-in functions??
On Mar 4, 2009, at 9:49 AM, Allen Wirfs-Brock wrote:
I'm not sure that there ever was a stated requirement that Function.prototype.name yield the same value that appears in the identifier position of a Function declaration/expression text produced by toString. If that was to be the case, then name offers very little added value as the identifier can be extracted from from the toString value with a fairly simple RegExp.
Historical note: name in SpiderMonkey and the Netscape progenitor predate ES3 and RegExps (RegExps based on Perl 4 were coming along before ES3 standardized Perl-5-ish RegExps).
Fairly simple regexps can do a great many things, as David-Sarah pointed out re: parseInt weakness. That's no reason for varying name from its obvious connotation if the primary use-case is getting the same name that follows 'function' in the toString result.
It always seemed to me that the real utility of the proposed name property was to provide additional descriptive information about functions that might be useful for debugger. The underscored prefix does provide this except for the obvious ambiguities with functions explicitly named in that manner. We did discuss this at the MV meeting in the context of name bind functions and object literal get/set functions and nobody seems concerned about the space in those names.
It's a roll of the dice; I recall saying we would have to implement and see how it went.
Use-case analysis needs user testing. If you think the use-case is a diagnostic informative identifying string to be formatted into a localized sentence, multiple words separate by spaces are problematic for l10n and ambiguity reasons.
It seems to me we should not be making stuff up here that has not already been implemented. If we must, we could try to get feedback from prototype 3.1 implementations. We can't afford to do too much of this late innovation, though, because we won't be able to get sufficient user testing for very much novelty, in the time alloted.
If we really want to establish a Function.prototype.name/Function.prototype.toString invariant then we need to also worry about what happens if Function.prototype.name is modified (it's [[Writable]]:true) and in particular if its value is set to a non-string. Do you want toString to specify that it just uses ToString() applied to the value of the name property?
Why in the world is name writable?
js> function f(){}
js> f.name
f js> f.name = 'g'
g js> f.name
f
It's not in Mozilla's implementations. AFAIK there's no precedent elsewhere that has name predefined yet writable.
Last fall, we dropped Function.prototype.arguments because of unresolved issues that were no more complex then these. Are we getting to the same point here?
I'm fine with dropping the Function name property from 3.1. We should develop a Harmony proposal that can be prototyped and tested at greater leisure if we drop it, not just drop it and ignore the progress made so far on this point.
Finally, I think the really important issue from an interoperability perspective is the toString issues that Maciej pointed out. Regardless of what we do with the name property I think we need to better specify it for consistent interoperability and compatibility with the existing web. I think the proposal for toString in my earlier message addresses those concerns.
It would be bad to overspecify, e.g. whitespace or comment preservation, or particular formatting. Existing code copes with various implementation artifacts. What is not good is the failure to produce anything compilable for a scripted function, or something that miscompiles to a function not isomorphic to the original.
Can I suggest that allowing writing to name may be helpful when
creating transparent wrapper functions?
We do a lot of this:
function wrapWithChangeNotification(key, fn) { return function() { this.willChangeValueForKey(key); var result= fn.apply(this, arguments); this.didChangeValueForKey(key); return result; } }
I'd love it if I could set the name on the new function to match the
original function.
On Wed, Mar 4, 2009 at 1:31 PM, Allen Wirfs-Brock < Allen.Wirfs-Brock at microsoft.com> wrote:
I'm fine with dropping the Function name property from 3.1
I think that might be best, although we would still need to define the toString name for all possible function creation scenarios.
+1. When in doubt, leave it out. Nothing else in the spec depends on <function>.name, nor do any of the real goals for ES3.1.
On Mar 4, 2009, at 1:38 PM, Jeff Watkins wrote:
Can I suggest that allowing writing to name may be helpful when
creating transparent wrapper functions?We do a lot of this:
function wrapWithChangeNotification(key, fn) { return function() { this.willChangeValueForKey(key); var result= fn.apply(this, arguments); this.didChangeValueForKey(key); return result; } }
I'd love it if I could set the name on the new function to match the
original function.
Why? I mean, do you expect to see that assigned name in a future
toString() result?
The integrity of name reflecting the declared identifier seems worth
something. Is this a case where anonymous function objects should have
no name property at all, allowing you to create one (even with high
integrity, using ES3.1's Object.defineProperty), while named function
expressions and function definitions should induce a function object
with a readonly name property?
We could certainly change Mozilla's implementations to allow name to
be written but there's a tension here between integrity and
mutability. It seems worth a bit more discussion.
On Mar 3, 2009, at 8:01 PM, Mark S. Miller wrote:
I like most of what you just proposed, except that I find it
surprising that a function's ".name" is not the identifier used by
".toString()" on that function. This same issue just came up on an
internal list at Google: Objecting that since ES3.1 specs that the
".name" for bound functions and literal getters and setters is not
an identifier, it would break .toString() if it were used in the
identifier position of a function's .toString().On Tue, Mar 3, 2009 at 7:35 PM, Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com
wrote: A quick post-script. We could also give Function.prototype.name a
different name, perhaps "identifier" if we don't want to trample
over the existing FF and Chrome implementations. Too bad "name" is
such a good name for this functionality.The other way to reconcile this is to retreat to keeping the name
"name", but having it always agree with the identifier used the
function's .toString(). If we do this, then we should choose a good
enough identifier mangling scheme for bound functions
("bind_<original-ident>") and literal getters and setters
("get_<ident>", "set_<ident>"), and use it in both the .name and in
the identifier position of .toString(). Ugly as this is, I think
it's better than having two different names associated with the same
function by two different parts of our API merely because we
couldn't agree on one.
This position makes sense to me. Although I don't think it is a hard
requirement for the name to match the identifier used in the
toString() serialization, I think it is simpler and more consistent to
do it this way.
On Mar 4, 2009, at 3:52 PM, Brendan Eich wrote:
On Mar 4, 2009, at 1:38 PM, Jeff Watkins wrote:
Can I suggest that allowing writing to name may be helpful when
creating transparent wrapper functions?We do a lot of this:
function wrapWithChangeNotification(key, fn) { return function() { this.willChangeValueForKey(key); var result= fn.apply(this, arguments); this.didChangeValueForKey(key); return result; } }
I'd love it if I could set the name on the new function to match
the original function.Why? I mean, do you expect to see that assigned name in a future
toString() result?The integrity of name reflecting the declared identifier seems worth
something. Is this a case where anonymous function objects should
have no name property at all, allowing you to create one (even with
high integrity, using ES3.1's Object.defineProperty), while named
function expressions and function definitions should induce a
function object with a readonly name property?We could certainly change Mozilla's implementations to allow name to
be written but there's a tension here between integrity and
mutability. It seems worth a bit more discussion.
The authors of Objective-J and the Capuccino framework have asked us
to either make Function.name mutable or else provide a way to
construct a function with a provided name. Since they use language
translation, they would like the debugger and other tools to reflect
the original declared names such as "[MyClassName
methodWithParam:andStuff:]", in other words Objective-C looking
methods. I don't know if language translation is the world's greatest
thing but it seemed like a valid use case to me when they suggested it.
, Maciej
On Mar 5, 2009, at 5:34 PM, Maciej Stachowiak wrote:
The authors of Objective-J and the Capuccino framework have asked us
to either make Function.name mutable or else provide a way to
construct a function with a provided name. Since they use language
translation, they would like the debugger and other tools to reflect
the original declared names such as "[MyClassName
methodWithParam:andStuff:]", in other words Objective-C looking
methods. I don't know if language translation is the world's
greatest thing but it seemed like a valid use case to me when they
suggested it.
In their code generation scheme, do they ever require the generated
function to have a particular non-global scope, or will global scope do?
If global only, then the Function constructor could make an instance
with mutable name, maybe. Not easy to spec given that in every other
respect the object returned by new Function is a function object, if
we want the spec to keep name immutable for declared and expressed
functions with names.
If local or global, we could make anonymous function expressions have
no name property at all. I'm warming up to this. We could do likewise
for the result of Function as well. Only declared functions and named
function expressions would have an intrinsic name property.
A number of questions/comments below
-----Original Message----- From: Brendan Eich Sent: Thursday, March 05, 2009 5:40 PM Subject: Re: name property for built-in functions??
On Mar 5, 2009, at 5:34 PM, Maciej Stachowiak wrote:
The authors of Objective-J and the Capuccino framework have asked us to either make Function.name mutable or else provide a way to construct a function with a provided name. Since they use language translation, they would like the debugger and other tools to reflect the original declared names such as "[MyClassName methodWithParam:andStuff:]", in other words Objective-C looking methods. I don't know if language translation is the world's greatest thing but it seemed like a valid use case to me when they suggested it.
Is the implication of the above that this name needs to be available to implementation specific debugger APIs? If so, is providing a "name" property on function objects likely to be sufficient for supporting such APIs?
In their code generation scheme, do they ever require the generated function to have a particular non-global scope, or will global scope do?
Are you really talking about "scopes" in the formal language sense here? Or are you asking whether or not there is a requirement for the values of all the name property to be globally different from each other. For the latter, if the debugger API provides function identity information that is distinct from the name then I would expect that name uniqueness would not be required.
If global only, then the Function constructor could make an instance with mutable name, maybe. Not easy to spec given that in every other respect the object returned by new Function is a function object, if we want the spec to keep name immutable for declared and expressed functions with names.
The spec'ing should be straight forward. All function construction funnels through the algorithm in 13.2 which already is defined to take a "Name" argument that is currently used to specify the value used to initialize the name property. It would be easy to extend the algorithm so that undefined means to not create the property, or to create is with a writable name property that is initialized to "anonymous" or whatever.
If local or global, we could make anonymous function expressions have no name property at all. I'm warming up to this. We could do likewise for the result of Function as well. Only declared functions and named function expressions would have an intrinsic name property.
Pulling in the list from an earlier message, here is the set of cases that I believe we need to fill in with the value of the name property (if it has one) and whether or not it is writable:
Defined by currently spec'ed name FunctionDeclaration the identifier from the declaration FunctionExpression with name the identifier from the function expression FunctionExpresion w/o name the empty string Object literal get/set "get <property name>" or "set <property name>"
Bound function "bind <target function name>" or " bind anonymous function" (new Function) "new Function"* Built-in specified name
Finally, if we have such a (writable) name property is the implication that toString should be required to use it in its generated representation?
On Mar 5, 2009, at 9:26 PM, Allen Wirfs-Brock wrote:
In their code generation scheme, do they ever require the generated function to have a particular non-global scope, or will global
scope do?Are you really talking about "scopes" in the formal language sense
here?
Yes -- does Objective-J generate lambdas in other functions which
refer to lexically scoped variables in enclosing functions. At least
one Ajax library I know of (EXT) does this using eval.
Or are you asking whether or not there is a requirement for the
values of all the name property to be globally different from each
other.
No.
For the latter, if the debugger API provides function identity
information that is distinct from the name then I would expect that
name uniqueness would not be required.
Agree, but let's hear from the Obj-J folks.
If global only, then the Function constructor could make an instance with mutable name, maybe. Not easy to spec given that in every other respect the object returned by new Function is a function object, if we want the spec to keep name immutable for declared and expressed functions with names.
The spec'ing should be straight forward. All function construction
funnels through the algorithm in 13.2 which already is defined to
take a "Name" argument that is currently used to specify the value
used to initialize the name property. It would be easy to extend
the algorithm so that undefined means to not create the property, or
to create is with a writable name property that is initialized to
"anonymous" or whatever.
I'm warmer than ever to this idea ;-).
Pulling in the list from an earlier message, here is the set of
cases that I believe we need to fill in with the value of the name
property (if it has one) and whether or not it is writable:Defined by currently spec'ed name FunctionDeclaration the identifier from the
declaration FunctionExpression with name the identifier from the function
expression FunctionExpresion w/o name the empty string
Or no name property at all, in the proposal we're talking about here.
Object literal get/set "get <property name>" or "set
<property name>" Bound function "bind <target function name>" or
" bind anonymous function"
With _ not space, right?
(new Function) "new Function"*
I thought we stuck at "" for this one.
Built-in specified name
Finally, if we have such a (writable) name property is the
implication that toString should be required to use it in its
generated representation?
The anonymous function expression carries no intrinsic name, so can't
name itself when decompiled without extra spec machinery.
A function object (remember joined function objects in ES3?) created
from the compiler-created immutable-shared function may or may not
have a name property in the proposal, but calling toString on a
function object created (to form a closure) should not, in my opinion,
get the value of the "name" property of that particular (or any other)
closure object.
Setting the name of the compiler-created function by assigning a
property to one of N (N>=1) unjoined function objects could be done.
No more "immutable" but the "shared" still applies. I do not favor
this, but it could be done. I suspect the Obj-J folks want it.
On Thu, Mar 5, 2009 at 11:18 PM, Brendan Eich <brendan at mozilla.com> wrote:
A function object (remember joined function objects in ES3?) created from the compiler-created immutable-shared function may or may not have a name property in the proposal, but calling toString on a function object created (to form a closure) should not, in my opinion, get the value of the "name" property of that particular (or any other) closure object.
Setting the name of the compiler-created function by assigning a property to one of N (N>=1) unjoined function objects could be done. No more "immutable" but the "shared" still applies. I do not favor this, but it could be done. I suspect the Obj-J folks want it.
I strongly object. Such sharing of state, enabled only by sharing the same function literal in the code, violates all notions of state isolation. It presents all the same hazards that the ES3 sharing of mutable RegExp literal objects had. The current draft spec repairs all such leaks. Let's not introduce another.
On Thu, Mar 5, 2009 at 11:18 PM, Brendan Eich <brendan at mozilla.com> wrote:
On Mar 5, 2009, at 9:26 PM, Allen Wirfs-Brock wrote:
Agree, but let's hear from the Obj-J folks.
Have you looked at the source code?
Garrett
On Mar 6, 2009, at 9:12 AM, Mark S. Miller wrote:
On Thu, Mar 5, 2009 at 11:18 PM, Brendan Eich <brendan at mozilla.com>
wrote:A function object (remember joined function objects in ES3?)
created from the compiler-created immutable-shared function may or may not have
a name property in the proposal, but calling toString on a function object
created (to form a closure) should not, in my opinion, get the value of the
"name" property of that particular (or any other) closure object.Setting the name of the compiler-created function by assigning a
property to one of N (N>=1) unjoined function objects could be done. No more
"immutable" but the "shared" still applies. I do not favor this, but it could
be done. I suspect the Obj-J folks want it.I strongly object. Such sharing of state, enabled only by sharing the same function literal in the code, violates all notions of state isolation. It presents all the same hazards that the ES3 sharing of mutable RegExp literal objects had. The current draft spec repairs all such leaks. Let's not introduce another.
I obviously agree, but let me agree more strongly. Huzzah!
No, sorry -- no time. What's your point? If you see something worth
describing, please do so. Otherwise: Let's hear from the Obj-J folks
anyway, the source does not speak or think.
On Fri, Mar 6, 2009 at 9:48 AM, Brendan Eich <brendan at mozilla.com> wrote:
No, sorry -- no time. What's your point? If you see something worth
My point? If you had read the source code, then you might have reason for waiting to hear from the objective-j folks to make a decision on [[Writable]] name. What could the reason be?
People do all sorts of things with javascript. Whether those things effectively and efficiently solve problems is something that can often be determined by looking at the problem juxtaposed against the source code without too much difficulty (this is depending on the fundamental complexity of the problem).
On Mar 6, 2009, at 12:41 PM, Garrett Smith wrote:
On Fri, Mar 6, 2009 at 9:48 AM, Brendan Eich <brendan at mozilla.com>
wrote:No, sorry -- no time. What's your point? If you see something worth
My point? If you had read the source code, then you might have reason for waiting to hear from the objective-j folks to make a decision on [[Writable]] name. What could the reason be?
I am waiting to hear from them. Are you reading what I'm writing? Yeesh.
No decision is being rushed here, but the point against mutable named-
function name property (both "named" and "name" are necessary in that
phrase) on which Mark and I agree stands independently of other
arguments. It might lose (I hope not), but it's fair to make now,
independently from any other correspondence on this topic. It is an
apple to any countervailing orange.
Now, I like apples better than oranges, perhaps Mark does too, but the
isolation argument that Mark emphasized is not just a matter of taste.
Just as an apple may be objectively more healthy to the average or
majority-demographic constitutional type, immutable function name may
be measurably more secure, or more efficient (both, I'd argue).
The utility of mutable name for anonymous functions is not at issue if
we do not define name at all on such functions -- this is the proposal
Allen and I were converging on. You can set name on such anonymous,
expressed functions to whatever value you like, delete it, shadow it
via .prototype/construction, etc.
The only issue remaining in this anonymous function case is whether
toString picks up the assigned name. For anonymous functions only,
this could be done without breaking the isolation property that
allowing mutation of the name initialized from the declared name of a
non-anonymous function would break. In fact it would seem independent:
anonymous function referenced by variable f:
- name can be set;
- if set to a value converting to the string "g", then f.toString()
returns "function g(...) {...}" (modulo whitespace).
named function expression or declaration, name is f:
- name cannot be set, deleted, or configured;
- f.toString() always returns a string starting "function f(...".
Does this help?
... groups.google.com/group/comp.lang.javascript/msg/6d266c0ddc64f9ec?dmode=source&output=gplain
Good stuff.
Off topic, too. If the goal is to hear from the Objective-J folks, let
them speak on the particular issue of mutable function name property.
General hype just adds noise and makes me grumpy. Let's talk about the
specific costs and benefits of function name property as proposed. And
yeah, I'd love to hear more about the Objective-J use-case.
Brendan Eich wrote:
The utility of mutable name for anonymous functions is not at issue if we do not define name at all on such functions -- this is the proposal Allen and I were converging on. You can set name on such anonymous, expressed functions to whatever value you like, delete it, shadow it via .prototype/construction, etc.
I think that's a good solution; it meets the Objective-J use case without introducing the mutability issue raised by MarkM.
The only issue remaining in this anonymous function case is whether toString picks up the assigned name. For anonymous functions only, this could be done without breaking the isolation property that allowing mutation of the name initialized from the declared name of a non-anonymous function would break. In fact it would seem independent:
anonymous function referenced by variable f:
- name can be set;
- if set to a value converting to the string "g", then f.toString() returns "function g(...) {...}" (modulo whitespace).
If name is set to a value that is not an Identifier, then the resulting string might not be a syntactically correct FunctionExpression or FunctionDeclaration.
Of course a possible response is "Don't do that". Since the code that is setting the name could do other things that would achieve the same effect (for example, setting 'toString'), a "Don't do that" answer may be adequate in this case. The function object can be sealed to prevent all such mutations.
David-Sarah Hopwood wrote:
Brendan Eich wrote:
The utility of mutable name for anonymous functions is not at issue if we do not define name at all on such functions -- this is the proposal Allen and I were converging on. You can set name on such anonymous, expressed functions to whatever value you like, delete it, shadow it via .prototype/construction, etc.
I think that's a good solution; it meets the Objective-J use case without introducing the mutability issue raised by MarkM.
The only issue remaining in this anonymous function case is whether toString picks up the assigned name. For anonymous functions only, this could be done without breaking the isolation property that allowing mutation of the name initialized from the declared name of a non-anonymous function would break. In fact it would seem independent:
anonymous function referenced by variable f:
- name can be set;
- if set to a value converting to the string "g", then f.toString() returns "function g(...) {...}" (modulo whitespace).
If name is set to a value that is not an Identifier, then the resulting string might not be a syntactically correct FunctionExpression or FunctionDeclaration.
Of course a possible response is "Don't do that".
I meant, "Don't rely on the result of toString being syntactically correct after setting the name property to a non-Identifier."; not necessarily "Don't set the name property to a non-Identifier."
On Mar 5, 2009, at 11:18 PM, Brendan Eich wrote:
On Mar 5, 2009, at 9:26 PM, Allen Wirfs-Brock wrote:
In their code generation scheme, do they ever require the generated function to have a particular non-global scope, or will global
scope do?Are you really talking about "scopes" in the formal language sense
here?Yes -- does Objective-J generate lambdas in other functions which
refer to lexically scoped variables in enclosing functions. At least
one Ajax library I know of (EXT) does this using eval.
I think they only care about new Function() constructed functions. At
least, this was the focus of the discussion I had with them.
For what it's worth - they only really need the ability to set the
name once, not to mutate it multiple times. So if making the property
mutable for everything seems distasteful, I think an alternate
function constructor that lets you provide a name (which is thereafter
immutable) would be an adequate solution. I would prefer that to
sometimes having a read-only name property and sometimes not. For
example:
Function.create("[Foo bar]", "param1", "param2", "code(); goes();
here();");
This would allow us to retain the name "anonymous" for functions
created without providing a name.
, Maciej
I have another concern about the potential interactions between the proposed name property and toString. Apparently, there is a known use case of eval'ing the result of toString'ing a function in order to create a new function. If we assign synthetic names such as "get_foo" or "set_foo" to syntactically defined getter/setter functions or allow a user to associate a name with an anonymous function which then appears in the toString representation will mean that eval will parse the toString result as a FunctionDeclaration rather than a FunctionExpression. For non-strict evals, that means that the synthetic name will get added to the Declaration Environment of the eval. Note that for indirect evals, the Declaration Environment is now the Global Environment but even for nested eval this possibility seems like a hazard that that most uses are not dealing with.
Of course, this issue already exists in ES3 for syntactically named functions and functions that are internally assigned the name "anonymous" so maybe these additions aren't actually making things much worse.
However, this concern along with Maciej's latest suggestions about Function.create pushes me further in the direction that we should hold off on adding a function name property in ES3.1. We still might want to consider enhancing the specification of toString to explicitly address the naming of functions created other than by a FunctionDeclaration/FunctionExpression. However, since some of the same issues arise there I'm inclined to leave it as implementation defined for ES3.1.
On Mar 8, 2009, at 10:28 AM, Allen Wirfs-Brock wrote:
I have another concern about the potential interactions between the
proposed name property and toString. Apparently, there is a known
use case of eval'ing the result of toString'ing a function in order
to create a new function. If we assign synthetic names such as
"get_foo" or "set_foo" to syntactically defined getter/setter
functions or allow a user to associate a name with an anonymous
function which then appears in the toString representation will mean
that eval will parse the toString result as a FunctionDeclaration
rather than a FunctionExpression.
But eval requires its first argument parse as a Program, and Programs
cannot consist entirely of, or begin with, an anonymous function
expression.
IOW, if someone is editing function source via toString/replace/eval,
they are not doing it portably per ES3 if the function originated as
an anonymous function expression.
In the case of an object literal, e.g.
js> var o = { get foo() {return 42}, set foo(x)
{print(arguments.callee)} };
js> uneval(o)
({get foo () {return 42;}, set foo (x) {print(arguments.callee);}})
js> o.foo
42 js> o.foo = 43
function (x) { print(arguments.callee); } 43
there is no standard "uneval" (SpiderMonkey has one) by which you
could hope to recover the getter and setter.
You could write such an uneval using 3.1's reflective meta-programming
API. Say you did: then there would be no way to give a property name
and a (different, assigned post-creation per the recent discussion)
intrinsic name to an initially-anonymous getter or setter function.
SpiderMonkey again:
js> var o = { get foo bar() {return 42}, set foo bar(x)
{print(arguments.callee)} };
js> uneval(o)
({get foo bar() {return 42;}, set foo bar(x)
{print(arguments.callee);}})
js> o.foo
42 js> o.foo = 43
function bar(x) { print(arguments.callee); } 43
Now you are quite right that the print(arguments.callee) in the setter
for property id foo (but with intrinsic name bar) has output a string
that is a function definition, if parsed as a whole program. But in
the context of o -- as the result of uneval(o) -- there is no problem,
provided you accept the (unusual but consistent) SpiderMonkey
extension which allows two names after the get or set.
Function context always matters, since anonymous functions are illegal
at top level of a program or function body, and named function
expressions moved to top level become function definitions.
For non-strict evals, that means that the synthetic name will get
added to the Declaration Environment of the eval. Note that for
indirect evals, the Declaration Environment is now the Global
Environment but even for nested eval this possibility seems like a
hazard that that most uses are not dealing with.
True, but again it seems your hypothesis starts with an anonymous
function being decorated with a name property, but eval of toString of
an anonymous function (without the name decoration, or run in an ES3
implementation) produces an anonymous function which standard eval
will reject.
Of course, this issue already exists in ES3 for syntactically named
functions and functions that are internally assigned the name
"anonymous" so maybe these additions aren't actually making things
much worse.
The "anonymous" botch is peculiar to the Function constructor. I like
Maciej's Function.create proposal, and it helps us avoid making more
bad law on the old "anonymous" hard case.
However, this concern along with Maciej's latest suggestions about
Function.create pushes me further in the direction that we should
hold off on adding a function name property in ES3.1.
Still with you on holding off for 3.1, but we are clearly making
progress via es-discuss toward a Harmonious proposal.
We still might want to consider enhancing the specification of
toString to explicitly address the naming of functions created other
than by a FunctionDeclaration/FunctionExpression. However, since
some of the same issues arise there I'm inclined to leave it as
implementation defined for ES3.1.
Agreed.
Allen Wirfs-Brock wrote:
I have another concern about the potential interactions between the proposed name property and toString. Apparently, there is a known use case of eval'ing the result of toString'ing a function in order to create a new function. If we assign synthetic names such as "get_foo" or "set_foo" to syntactically defined getter/setter functions or allow a user to associate a name with an anonymous function which then appears in the toString representation will mean that eval will parse the toString result as a FunctionDeclaration rather than a FunctionExpression.
For non-strict evals, that means that the synthetic name will get added to the Declaration Environment of the eval. Note that for indirect evals, the Declaration Environment is now the Global Environment but even for nested eval this possibility seems like a hazard that that most uses are not dealing with.
I don't see why this is an interaction between 'name' and 'toString'. Isn't this issue independent of whether 'name' is present?
-----Original Message----- From: es-discuss-bounces at mozilla.org [mailto:es-discuss- bounces at mozilla.org] On Behalf Of David-Sarah Hopwood
I don't see why this is an interaction between 'name' and 'toString'. Isn't this issue independent of whether 'name' is present?
Yes, but it was the existence of the name property that motivated us to assign function names for getters/setters, binde, and new functions. In addition, the opinions expressed on this thread seem to lean towards the value of the name property also showing up as the function name in the toString result.
There are enough issues about the name property that I'm going to assume that it will be dropped from ES3.1, so I'm going to prepare a set of changes that will remove it.
A related but separable issue as to whether the existing definition of Function.prototype.toString should be embellished to say something about the name used in the "implementation-dependent representation". Assuming we are dropping the name property and will target this sort of functionality for post ES3.1. I'm inclined to just leave toString alone for ES3.1.
On Sun, Mar 8, 2009 at 12:10 PM, Brendan Eich <brendan at mozilla.com> wrote:
On Mar 8, 2009, at 10:28 AM, Allen Wirfs-Brock wrote:
I have another concern about the potential interactions between the proposed name property and toString. Apparently, there is a known use case of eval'ing the result of toString'ing a function in order to create a new function. If we assign synthetic names such as "get_foo" or "set_foo" to syntactically defined getter/setter functions or allow a user to associate a name with an anonymous function which then appears in the toString representation will mean that eval will parse the toString result as a FunctionDeclaration rather than a FunctionExpression.
But eval requires its first argument parse as a Program, and Programs cannot consist entirely of, or begin with, an anonymous function expression.
IOW, if someone is editing function source via toString/replace/eval, they are not doing it portably per ES3 if the function originated as an anonymous function expression.
In the case of an object literal, e.g.
js> var o = { get foo() {return 42}, set foo(x) {print(arguments.callee)} }; js> uneval(o) ({get foo () {return 42;}, set foo (x) {print(arguments.callee);}}) js> o.foo 42 js> o.foo = 43 function (x) { print(arguments.callee); } 43
there is no standard "uneval" (SpiderMonkey has one) by which you could hope to recover the getter and setter.
You could write such an uneval using 3.1's reflective meta-programming API. Say you did: then there would be no way to give a property name and a (different, assigned post-creation per the recent discussion) intrinsic name to an initially-anonymous getter or setter function. SpiderMonkey again:
js> var o = { get foo bar() {return 42}, set foo bar(x) {print(arguments.callee)} }; js> uneval(o) ({get foo bar() {return 42;}, set foo bar(x) {print(arguments.callee);}}) js> o.foo 42 js> o.foo = 43 function bar(x) { print(arguments.callee); } 43
Now you are quite right that the print(arguments.callee) in the setter for property id foo (but with intrinsic name bar) has output a string that is a function definition, if parsed as a whole program. But in the context of o -- as the result of uneval(o) -- there is no problem, provided you accept the (unusual but consistent) SpiderMonkey extension which allows two names after the get or set.
Function context always matters, since anonymous functions are illegal at top level of a program or function body, and named function expressions moved to top level become function definitions.
For non-strict evals, that means that the synthetic name will get added to the Declaration Environment of the eval. Note that for indirect evals, the Declaration Environment is now the Global Environment but even for nested eval this possibility seems like a hazard that that most uses are not dealing with.
True, but again it seems your hypothesis starts with an anonymous function being decorated with a name property, but eval of toString of an anonymous function (without the name decoration, or run in an ES3 implementation) produces an anonymous function which standard eval will reject.
Of course, this issue already exists in ES3 for syntactically named functions and functions that are internally assigned the name "anonymous" so maybe these additions aren't actually making things much worse.
The "anonymous" botch is peculiar to the Function constructor. I like Maciej's Function.create proposal, and it helps us avoid making more bad law on the old "anonymous" hard case.
I (finally) realized it would be useful to allow setting the name dynamically.
In a good number of cases, a closure is used where Function.prototype.bind() would be used. In this case, a generically-named or anonymous function is created and returned. It is not possible to parametrize the function name.
EventPublisher.fireEvent = function(publisher) {
return function publisher.eventName+"Handler" { // code here. }; };
The square bracket is just pseudo. The syntax is incompatible.
Maciej' Function.create proposal:-
Function.create("[Foo bar]", "param1", "param2", "code(); goes(); here();");
- uses strings to create a function. Escaping strings in strings is awkward to read and write. Refactoring a function into strings to arguments to Function.create would be tedious and error-prone. Especiall if the soure already contains strings in strings (html = "<p id='p'>p</p>". Using with strings to build functions cumbersome.
Eval uses the calling context's scope. I do not know what the scope would be for a function created with Function.create. To use the calling context's scope would seem to be not secure. However, it would seem necessary to wrap a function.
Possible alternative:- Function.create( name, fun[, context] );
Garrett
On Mar 10, 2009, at 8:29 PM, Garrett Smith wrote:
[...]
Maciej' Function.create proposal:-
Function.create("[Foo bar]", "param1", "param2", "code(); goes();
here();");
- uses strings to create a function. Escaping strings in strings is awkward to read and write. Refactoring a function into strings to arguments to Function.create would be tedious and error-prone. Especiall if the soure already contains strings in strings (html = "<p id='p'>p</p>". Using with strings to build functions cumbersome.
Agreed. That would be messy.
Eval uses the calling context's scope. I do not know what the scope would be for a function created with Function.create. To use the calling context's scope would seem to be not secure. However, it would seem necessary to wrap a function.
Possible alternative:- Function.create( name, fun[, context] );
I can't think of a better alternative at the moment. What's weird
about such notation though, is that Function.create
doesn't quite
fit the description any longer. Function object is being created
during evaluation, before it's being passed to Function.create
as
the last argument. What Function.create
does is merely setting/
modifying an Identifier on a given function. It seems that
Function.setName
(or some such) would convey an intent better.
Function.setName('name', function(){ ... });
On a side note, what happens when you pass a function with already
existing identifier? Would it be overwritten or left intact?
Function.create('foo', function bar(){ });
And finally, I assume that some kind of error would be thrown if
name
string can not be parsed as an identifier?
On Tue, Mar 10, 2009 at 6:22 PM, Juriy Zaytsev <kangax at gmail.com> wrote:
On Mar 10, 2009, at 8:29 PM, Garrett Smith wrote: [...]
[...]
Possible alternative:- Function.create( name, fun[, context] );
I can't think of a better alternative at the moment. What's weird about such notation though, is that
Function.create
doesn't quite fit the description any longer. Function object is being created during evaluation, before it's being passed toFunction.create
as the last argument. WhatFunction.create
does is merely setting/modifying an Identifier on a given function. It seems thatFunction.setName
(or some such) would convey an intent better.
Sorry, no, that was not the intent. The intent would be to create a new function object based on |fun|, using the same scope.
Function.setName('name', function(){ ... }); On a side note, what happens when you pass a function with already existing identifier? Would it be overwritten or left intact?
Returns a new function, |fun| is unchanged.
Function.create('foo', function bar(){ }); And finally, I assume that some kind of error would be thrown if
name
string can not be parsed as an identifier?
Sounds reasonable to me, though Maciej' proposal seems to attemp just that:-
Function.create("[Foo bar]", "param1", "param2", "code(); goes(); here();");
would the identifier be [Foo bar]?
That would result in a conformance clash with toString (which is spec'd in 3.0 to return a FunctionDeclaration, which implementations don't do with an anonymous function).
Garrett
Garrett Smith wrote:
I (finally) realized it would be useful to allow setting the name dynamically.
In a good number of cases, a closure is used where Function.prototype.bind() would be used. In this case, a generically-named or anonymous function is created and returned. It is not possible to parametrize the function name.
EventPublisher.fireEvent = function(publisher) {
return function publisher.eventName+"Handler" { // code here. }; };
The square bracket is just pseudo. The syntax is incompatible.
Maciej' Function.create proposal:-
Function.create("[Foo bar]", "param1", "param2", "code(); goes(); here();");
- uses strings to create a function. Escaping strings in strings is awkward to read and write. Refactoring a function into strings to arguments to Function.create would be tedious and error-prone. Especiall if the soure already contains strings in strings (html = "<p id='p'>p</p>". Using with strings to build functions cumbersome.
Eval uses the calling context's scope. I do not know what the scope would be for a function created with Function.create. To use the calling context's scope would seem to be not secure. However, it would seem necessary to wrap a function.
Possible alternative:- Function.create( name, fun[, context] );
I don't see the problem here that would require overriding the context. The scope used by fun would be its original lexical scope. In the example above:
EventPublisher.fireEvent = function(publisher) { return Function.create(publisher.eventName + "Handler", function(ev) { // code here // can refer to 'publisher', etc. if needed }); };
All the hypothetical Function.create does is to create a new function that behaves the same as its fun argument, but with a different name. The .name property of all function objects would be non-[[Writable]] and non-[[Configurable]].
Whether this is actually needed, I'm not sure, but it has all of the functional and security properties I've seen stated as desirable so far in this thread.
On Wed, Mar 11, 2009 at 3:31 AM, David-Sarah Hopwood <david.hopwood at industrial-designers.co.uk> wrote:
Garrett Smith wrote:
[...]
Maciej' Function.create proposal:-
Function.create("[Foo bar]", "param1", "param2", "code(); goes(); here();");
[...]
Possible alternative:- Function.create( name, fun[, context] );
I don't see the problem here that would require overriding the context.
No problem there.
The problem was with the other (Maciej') Function.create.
Function.create param |code|, as a string would be used to build a Function. That function would have to have global scope. To use the calling context's scope (as eval does) would be a security issue.
To not use the calling context's scope would not allow for wrapping functions (Jeff Watkins' use case).
The scope used by fun would be its original lexical scope. In the example above:
EventPublisher.fireEvent = function(publisher) { return Function.create(publisher.eventName + "Handler", function(ev) { // code here // can refer to 'publisher', etc. if needed }); };
All the hypothetical Function.create does is to create a new function that behaves the same as its fun argument, but with a different name. The .name property of all function objects would be non-[[Writable]] and non-[[Configurable]].
Whether this is actually needed, I'm not sure, but it has all of the functional and security properties I've seen stated as desirable so far in this thread.
I agree on both points. It is secure this way, but I am not sure if it is needed.
If used for debugging, what would the debugger step into for:-
var f2 = Function.create("f2", fun)(0);
function fun(i) { if(i === 0) throw Error("zero"); }
?
Garrett
Because we have introduced a "name" property for function objects we have to specify what values the built-in functions in Section 15 each have for this property. Note that the value of this property is intended to be a descriptive name and is not necessarily a simple identifier. We have already taken advantage of this in specify the "name" of functions created using Function.prototype.bind.
So what should name property values be for a built-in function such as Array.prototype.printString? The straight forward thing to do is to say it is "printString". However, it would be potentially more useful for debugging purposes if it was "Array.prototype.printString".
Thoughts? I'm probably going to specify that simple identifier unless I hear a strong response in favor of using the fully qualified name.