ES4 draft: Function
-----Original Message----- From: Erik Arvidsson [mailto:erik.arvidsson at gmail.com] Sent: 10. mars 2008 17:31 To: Lars Hansen Cc: es4-discuss Discuss Subject: Re: ES4 draft: Function
What is the reason to make the thisObj param to bind optional?
Symmetry with call and apply and a consequence of the
definition given in the proposals page (link below, it's
near the bottom). But I agree that it seems misguided.
Will change this unless there's opposition to it.
-----Original Message----- From: es4-discuss-bounces at mozilla.org [mailto:es4-discuss-bounces at mozilla.org] On Behalf Of Lars Hansen Sent: 10. mars 2008 18:46 To: Erik Arvidsson Cc: es4-discuss Discuss Subject: RE: ES4 draft: Function
-----Original Message----- From: Erik Arvidsson [mailto:erik.arvidsson at gmail.com] Sent: 10. mars 2008 17:31 To: Lars Hansen Cc: es4-discuss Discuss Subject: Re: ES4 draft: Function
What is the reason to make the thisObj param to bind optional?
Symmetry with call and apply and a consequence of the definition given in the proposals page (link below, it's near the bottom). But I agree that it seems misguided.
Will change this unless there's opposition to it.
But is null an acceptable non-default value for thisObj (meaning, use the global object in the bind method's scope)?
On 3/10/08, Lars Hansen <lhansen at adobe.com> wrote:
First draft of the spec for the Function class. Please comment.
Suggestion: deprecate the Function constructor and static invoke().
Almost all of its uses are better handled by function expressions and, in those cases where eval() in required, one can use eval().
There are valid use cases for new Function (...) and Function(...). One that comes to mind is getting an attribute in DOM and make it into an event handler. Yes, the Function constructor and meta::invoke can be replaced by eval but Function needs to be there for ES3 compatibility.
On 3/10/08, Erik Arvidsson <erik.arvidsson at gmail.com> wrote:
There are valid use cases for new Function (...) and Function(...). One that comes to mind is getting an attribute in DOM and make it into an event handler. Yes, the Function constructor and meta::invoke can be replaced by eval but Function needs to be there for ES3 compatibility.
...which is why I wrote "deprecate," rather than "remove." In other words, I'm suggesting treating the Function constructor the way we're treating Function.arguments.
-----Original Message----- From: zeppieri at gmail.com [mailto:zeppieri at gmail.com] On Behalf Of Jon Zeppieri Sent: 10. mars 2008 20:39 To: Lars Hansen Cc: es4-discuss Discuss Subject: Re: ES4 draft: Function
On 3/10/08, Lars Hansen <lhansen at adobe.com> wrote:
First draft of the spec for the Function class. Please comment.
Suggestion: deprecate the Function constructor and static invoke().
Almost all of its uses are better handled by function expressions and, in those cases where eval() in required, one can use eval().
I think there are three points to be made here. The first is that the Function constructor provides functionality that eval does not, namely, creating new functions that are closed in the global environment only. Erik made the argument that this is sometimes useful; I agree.
The second point is about deprecation. TG1 has had a difficult time with deprecation in general. It is not clear that deprecation means anything on the web, except /maybe/ in the very long term. The fact that we deprecate something has no bearing on existing content, and new engines will need to support old behavior. So though TG1 finally (on my insistence) deprecated the arguments object, it was with a shrug, and it would be surprising to me if the deprecation clause makes it into the final spec, as it has no real impact. (I actually wanted to remove the arguments object from ES4 so that ES4-only implementations would not have to implement it at all, to be replaced by rest arguments and "this function".)
The third point is, why deprecate that particular functionality? It's not like it costs much at all in terms of spec space or implementation complexity. Eval already requires hooks into a run-time compiler, which is where the heavy lifting goes.
On Tue, Mar 11, 2008 at 10:49 AM, Lars Hansen <lhansen at adobe.com> wrote:
I think there are three points to be made here. The first is that the Function constructor provides functionality that eval does not, namely, creating new functions that are closed in the global environment only. Erik made the argument that this is sometimes useful; I agree.
Doesn't global.eval() meet this requirement? From the overview document:
=== ES4 additionally defines eval as a function bound in the global environment that can be called indirectly through that environment (e.g., as window.eval(s) in a web browser) or whose value can be read and passed around, stored in other variables and so on, and called as a plain function: var e = eval ... e(myprog) In both of these cases, the evaluation takes place in the global environment in which the eval function is defined.
The second point is about deprecation. TG1 has had a difficult time with deprecation in general. It is not clear that deprecation means anything on the web, except /maybe/ in the very long term. The fact that we deprecate something has no bearing on existing content, and new engines will need to support old behavior.
Deprecation isn't solely (or even primarily) for the benefit of implementors. It tells the programmer: "This probably isn't what you want, and even if it does what you want, there's a more sane way to do it."
What does new Function() get you that eval doesn't (taking into consideration global.eval())? For the most part, it's just syntactic... well, not sugar, because it doesn't actually result in a cleaner syntactic construction. 'Syntactic salt' still suggests some kind of enhancement... I'd call it a syntactic booger.
To the extent that it isn't just a special case of eval(), it's useless. You could, for example, define a subclass of Function that might do something potentially useful. I notice that you can't instrument the normal call functionality, since the instance version of meta::invoke() is final, but you might be able to instrument apply() for some potentially useful debugging purpose. But to make use of it, you would need to construct your functions using 'new' and incur the enormous performance penalty -- not to mention the fact that since all functions so created are closed in the global environment, it's completely worthless for functions that need to close over lexical bindings.
So though TG1 finally (on my insistence) deprecated the arguments object, it was with a shrug, and it would be surprising to me if the deprecation clause makes it into the final spec, as it has no real impact. (I actually wanted to remove the arguments object from ES4 so that ES4-only implementations would not have to implement it at all, to be replaced by rest arguments and "this function".)
I sympathize.
The third point is, why deprecate that particular functionality? It's not like it costs much at all in terms of spec space or implementation complexity. Eval already requires hooks into a run-time compiler, which is where the heavy lifting goes.
Again -- this isn't for the benefit of implementors.
-----Original Message----- From: zeppieri at gmail.com [mailto:zeppieri at gmail.com] On Behalf Of Jon Zeppieri Sent: 11. mars 2008 09:33 To: Lars Hansen Cc: es4-discuss Discuss Subject: Re: ES4 draft: Function
On Tue, Mar 11, 2008 at 10:49 AM, Lars Hansen <lhansen at adobe.com> wrote:
I think there are three points to be made here. The first is that
the Function constructor provides functionality that eval does not,
namely, creating new functions that are closed in the global environment only. Erik made the argument that this is sometimes useful; I agree.
Doesn't global.eval() meet this requirement? From the overview document:
=== ES4 additionally defines eval as a function bound in the global environment that can be called indirectly through that environment (e.g., as window.eval(s) in a web browser) or whose value can be read and passed around, stored in other variables and so on, and called as a plain function: var e = eval ... e(myprog) In both of these cases, the evaluation takes place in the global environment in which the eval function is defined.
You're right, I forgot about global.eval as a workaround.
The second point is about deprecation. TG1 has had a difficult
time
with deprecation in general. It is not clear that deprecation means
anything on the web, except /maybe/ in the very long term. The
fact
that we deprecate something has no bearing on existing content, and
new engines will need to support old behavior.
Deprecation isn't solely (or even primarily) for the benefit of implementors. It tells the programmer: "This probably isn't what you want, and even if it does what you want, there's a more sane way to do it."
Sure, nobody argues about that per se, but I don't see the spec as being the place to take an ideological stand about whether global.eval is cleaner than 'new Function', if taking a stand doesn't gain practical implementations anything at all. The reality is that 'new Function' and 'arguments' are available in all implementations, they are in wide-spread use, and their use will be propagated as long as implementations support them. Maybe if they are deprecated in the spec their use will see some decline; maybe ditto if better, alternative features are added to the language. I have more faith in the latter than in the former.
I don't really care about 'new Function' as it's just another API to functionality that will exist anyway, and 'new Function' is comparatively clean -- I don't agree that it is significantly less sane than global.eval. But I and others do care about 'arguments', so we have rest arguments and 'this function'; we do care about the operator form of 'eval', so there's been some discussion about whether to simply outlaw its use inside classes. These are better ways to make progress than paper deprecation, IMO.
I promise not to drag out this discussion, since no one else seems to be interested in it.
On Tue, Mar 11, 2008 at 12:16 PM, Lars Hansen <lhansen at adobe.com> wrote:
Sure, nobody argues about that per se, but I don't see the spec as being the place to take an ideological stand about whether global.eval is cleaner than 'new Function', if taking a stand doesn't gain practical implementations anything at all.
I'm not trying to make an ideological stand -- or, at least, not a particularly controversial one. I put far too much stress on syntax in my last message. The more important objection to 'new Function' concerns its semantics. The Function constructor has an awkward status in the language. Most objects are constructed by calling a constructor or by using a literal syntax, the semantics of which can be specified in terms of constructor call + accessor calls. E.g.:
[a, b] has the same semantics as
let (t = new Array()) (t[0] = a, t[1] = b, t)
...whereas you cannot, in the general case, locally rewrite a function expression in terms of 'new Function.' Also, there's the point I did raise in my last message: while you can subclass function, there doesn't appear to be much point in actually doing so -- precisely because most function construction does not go through the Function constructor.
The reality is that 'new Function' and 'arguments' are available in all implementations, they are in wide-spread use, and their use will be propagated as long as implementations support them. Maybe if they are deprecated in the spec their use will see some decline; maybe ditto if better, alternative features are added to the language. I have more faith in the latter than in the former.
These options aren't mutually exclusive, and I don't see the harm in deprecating this stuff. Now, if someone will offer a defense of 'new Function,' that's a different story. I am not trying to be controversial here.
I don't really care about 'new Function' as it's just another API to functionality that will exist anyway, and 'new Function' is comparatively clean -- I don't agree that it is significantly less sane than global.eval. But I and others do care about 'arguments', so we have rest arguments and 'this function'; we do care about the operator form of 'eval', so there's been some discussion about whether to simply outlaw its use inside classes. These are better ways to make progress than paper deprecation, IMO.
No question that 'arguments' is a more important issue.
Why doesn't Function have something like apply that does the same as in a new expression, i.e. allocate-init-and-apply? To put it another way: given arguments in an array, I want to write:
F.thisThing(args) and have it mean the same as new F(args[0], args[1], ... args[n-1])
Or is what happens behind the veil of object creation detailed enough that I can write a facsimile of it with apply? I guess something like:
var x = {}; x.prototype = F.prototype; x = F.apply(x, args) || x;
But why force me to guess? No doubt I am wrong.
Dominic
Well it does, apparently it was called the "splat" operator, which (to me) sounds a better than "spread". I think it works like:-
var args = [12, true]; new C(...args);
function C( count, isSemiAnnual) {
}
- Maybe one of guys writing the specs can comment on that.
It can be hacked in ES3:-
/**
* @param {Function} fun constructor to be invoked.
* @param {Array} args arguments to pass to the constructor.
* Instantiates a constructor and uses apply().
*/
newApply : function(fun, args) {
if(arguments.length === 0) return;
var f = arguments.callee, i;
f.prototype = fun.prototype;// Copy prototype.
f.prototype.constructor = fun;
i = new f;
fun.apply(i, args); // Apply the original constructor.
return i;
},
Garrett
Neat! Thanks for the link.
Dominic
I agree with Lars on this issue for exactly the same reasons as what he stated.
Waldemar
Here are my comments on this section:
static public function apply(fn /: function/, thisArg: Object=null, argArray: Object=null) static public function bind(method /: function/, thisObj: Object=null, ...args) static public function call(fn /: function/, thisObj: Object=null, ...args) prototype function apply(/*this: function, */ thisArg=undefined, argArray=undefined) prototype function bind(/*this: function, */ thisObj=undefined, ...args) prototype function call(/*this: function, */ thisObj=undefined, ...args)
What does "/: function/" mean here? Are these arguments required to have the function type or not?
Although apply is redundant in the presence of the splat operator, I see no harm in keeping it for consistency with ES3.
Implementation
The implementation of the meta function |invoke| is implementation-dependent.
Omit the implementation section altogether. Saying "implementation-dependent" is misleading here, as its behavior should not be implementation-dependent.
intrinsic function apply(thisArg: Object=null, argArray: Object=null) Function.apply(this, thisArg, argArray);
intrinsic function bind(thisObj: Object=null, ...args) Function.helper::bind(this, thisObj, args);
intrinsic function call(thisObj: Object=null, ...args) Function.apply(this, thisObj, args);
The middle one is not like the other two. Hmmm.... another use case for the splat operator.
Waldemar
-----Original Message----- From: Waldemar Horwat [mailto:waldemar at google.com] Sent: 13. mars 2008 16:01 To: Lars Hansen Cc: es4-discuss Discuss Subject: Re: ES4 draft: Function
static public function apply(fn /: function/, ...) static public function bind(method /: function/, ...) static public function call(fn /: function/, ...) ...
What does "/: function/" mean here? Are these arguments required to have the function type or not?
That is addressed in the NOTES section at the top of the document:
- The annotation '/: function/' below looks like that because the reference implementation does not yet accept plain 'function' as a type annotation to mean 'anything callable' (ticket #153).
That is, the arguments are required to be callable. (The reason it shows up in the draft spec is that the code has been pulled out of the reference implementation. (I could add code to the code snarfer that removes the /* and the */, maybe.))
What it means to be callable is addressed in another note near the top:
<NOTE> Host functions may also not be instances of ''Function'' or its
subclasses, but must to some extent behave as if they are (see <XREF target="Host objects">). However, host functions need not provide ''meta::invoke'' methods to be callable. The type ''function'', defined elsewhere, matches invokable host functions even if they do not have a ''meta::invoke'' method.
Implementation
The implementation of the meta function |invoke| is implementation-dependent.
Omit the implementation section altogether. Saying "implementation-dependent" is misleading here, as its behavior should not be implementation-dependent.
I understand the objection (you've made the point elsewhere as well) and I will consider a different wording/structure.
Thanks for the comments.
It seems to me that a function is a callable object, not the other way around. As if a Function were an implementation of Callable, where callable was an interface.
For programs to be concerned more with the object's capability -- what it can do -- not who constructed it.
Considering how that would affect the toString method: "The intrinsic toString method converts the executable code of the function to a string representation"
Some objects are callable, but the source code isn't avaiable. Object such as window.addEventListener, in a modern browser.
This implementation of toString, quoted above, would be appropriate for Function, but not necessarily all Callable objects, such as window.alert in a browser:-
javascript:void(Function.prototype.call.call(alert, window, alert));
-G
2008/3/10 Lars Hansen <lhansen at adobe.com>:
Draft 2 of the spec for the Function class. Changelog near the beginning; several small changes only.
First draft of the spec for the Function class. Please comment.