Draft of Function.prototype.bind.
With the formatting from the word doc, as converted by other tools: 15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, …]])
The bind method takes one or more arguments, thisArg * and (optionally) * arg1, arg2, etc, and returns a new function object by performing the following steps:
- Let T be thisArg.
2. Let G be the this object.
3. If IsCallable(G) is false, throw a TypeError exception.
4. Let A be a new (possibly empty) internal list of all of the
argument values provided after thisArg (arg1, arg2 etc), in
order.
5. Create a new native ECMAScript object and let F be that object.
6. Set the [[Class]] property of F to "Function".
7. Set the [[Prototype]] property of F to the original Function
prototype object as specified in 15.3.3.1.
8. Set the [[Call]] property of F as described in 15.3.4.5.1.
9. Set the [[Construct]] property of F as described in 15.3.4.5.2.
10. The [[Scope]] property of F has no observable effect, and so can
be ignored.
11. If the [[Class]] property of G is "Function", then
- Get the length property of G.
- Let L be Result(11a) minus the length of A.
- Set the length property of F to either 0 or L, whichever is larger.
- Else set the length property of F to 0.
- The length property of F is given attributes as specified in 15.3.5.1.
- Set the [[Extensible]] property of *F *to true.
- If the [[Class]] property of G is "Function", then
- Get the prototype property of G
- Set the prototype property of F to Result(15a).
- Else
- Create a new object as would be constructed by the expression *new Object()*where Object is the standard built-in constructor with that name.
- Set the constructor property of Result(16a) to F. This property has attributes { [[Writable]]: true, [[Enumerable]]: * false*, [[Configurable]]: true }.
- Set the prototype property of F to Result(16a).
- The prototype property of F is given attributes as specified in 15.3.5.2.
- Return F.
15.3.4.5.1 [[Call]]
Algorithm for the [[Call]] method of a function F returned from the bindmethod:
When executed with zero or more arguments, F uses the values of T, Gand A that were associated with it at its creation, and the following steps are taken:
- Let Args be a new internal list containing the same values as the list A in the same order followed by the argument list passed to Fin the same order. 2. Invoke the [[Call]] method of F providing T as the this value and providing Args as the arguments. 3. Return Result(3).
15.3.4.5.2 [[Construct]]
Algorithm for the [[Construct]] method of a function F returned from the * bind* method:
When executed with zero or more arguments, F uses the values of G and *A
-
that were associated with it at its creation, and the following steps are taken:
- If G has no [[Construct]] method, a TypeError exception is thrown. 2. Let Args be a new internal list containing the same values as the list A in the same order followed by the argument list passed to Fin the same order. 3. Invoke the [[Construct]] method of F providing undefined as the this value and providing Args as the arguments. 4. Return Result(3).
Mike Shaver wrote:
On Mon, Nov 3, 2008 at 12:32 PM, David-Sarah Hopwood <david.hopwood at industrial-designers.co.uk> wrote:
An object that was previously a callable nonfunction in some browser, can always be compatibly changed into a real function instead.
Does that mean that RegExp.prototype has as its prototype Function.prototype, for those implementations which have callable RegExps?
It's not clear to me that it is conformant to ES3 for RegExp objects to be callable. The behaviour of internal methods for native objects is fully defined by the spec; it's only host objects for which an implementation has latitude to define additional internal methods:
Section 8.6.2
The following table summarises the internal properties used by this
specification. The description indicates their behaviour for native
ECMAScript objects. Host objects may implement these internal methods
with any implementation-dependent behaviour, or it may be that a host
object implements only some internal methods and not others.
[...]
[[Call]] |
a list of argument values provided by the caller |
Executes code associated with the object. Invoked via a function
call expression. Objects that implement this internal method are
called /functions/.
That is, native objects that implement [[Call]] must be functions.
On Nov 3, 2008, at 6:50 PM, David-Sarah Hopwood wrote:
That is, native objects that implement [[Call]] must be functions.
No, see 16, second list, second bullet:
"An implementation may provide additional types, values, objects,
properties, and functions beyond those described in this
specification. This may cause constructs (such as looking up a
variable in the global scope) to have implementation-defined behaviour
instead of throwing an error (such as ReferenceError)."
See also 11.4.3 The typeof Operator (second to last table row).
Brendan Eich wrote:
On Nov 3, 2008, at 11:32 AM, David-Sarah Hopwood wrote:
Mark S. Miller wrote:
First, I'd like to thank Richard Cornford, cc'ed, who provided the earlier draft of Function.prototype.bind that grew into this one. Thanks!
Below, I modified Richard's draft according to our agreements in Redmond. But I'm not happy with its complexity. If we instead specify that we test in step 3 whether the [[Class]] of G is "Function", the rest of bind() becomes much easier to specify. Should we? The only functionality lost is the ability to use bind() as a generic applied to callable non-functions. Do we care whether the built-in bind() can handle these?
We should consider simply outlawing callable nonfunctions in ES3.1.
No, that is incompatible with every browser-based DOM implementation I know of.
An object that was previously a callable nonfunction in some browser, can always be compatibly changed into a real function instead.
Proof? Evidence? A hand-wavey demo?
It's completely trivial, but if you want a hand-wavey demo:
function makeHTMLCollection(underlying) { function collection(nameOrIndex) { // I think this is how MSIE behaves: return typeof nameOrIndex === 'string' ? underlying.namedItem(nameOrIndex) : underlying.item(nameOrIndex); } collection.namedItem = function(name) { return underlying.namedItem(name); } collection.item = function(index) { return underlying.index(index); }
// define any other non-standard methods
// should use a getter here if the length can change
collection.length = underlying.length;
return collection;
}
On Nov 3, 2008, at 7:16 PM, David-Sarah Hopwood wrote:
It's completely trivial, but if you want a hand-wavey demo:
function makeHTMLCollection(underlying) { function collection(nameOrIndex) { // I think this is how MSIE behaves: return typeof nameOrIndex === 'string' ? underlying.namedItem(nameOrIndex) : underlying.item(nameOrIndex); } collection.namedItem = function(name) { return underlying.namedItem(name); } collection.item = function(index) { return underlying.index(index); }
// define any other non-standard methods
// should use a getter here if the length can change collection.length = underlying.length;
return collection; }
You are once again missing the point: IE and (because of IE's
dominance) other browsers have callable host objects for which typeof
does not return "function". Changing these as you sketch above is an
incompatible change that may break real web content.
There is evidence for this, because Mozilla's regexps used to report
typeof-type "function" and so fell into logic wanting only a function,
not a callable host object. Also, alert in the IE DOM is not a
function, and it has typeof-type "object", but it is of course callable.
Yes, that means there is a de-facto standard: only function objects
report typeof "function".
But the relevant de-facto standard here is that host objects may be
callable, and JS code on the web knows this.
Brendan Eich wrote:
On Nov 3, 2008, at 6:50 PM, David-Sarah Hopwood wrote:
That is, native objects that implement [[Call]] must be functions.
No, see 16, second list, second bullet:
"An implementation may provide additional types, values, objects, properties, and functions beyond those described in this specification. This may cause constructs (such as looking up a variable in the global scope) to have implementation-defined behaviour instead of throwing an error (such as ReferenceError)."
So what does "Objects that implement this internal method are called functions." in the description of [[Call]] mean, then? If it is not true for native objects (which is what the section claims to be describing), then it is simply incorrect.
Brendan Eich wrote:
On Nov 3, 2008, at 7:16 PM, David-Sarah Hopwood wrote:
It's completely trivial, but if you want a hand-wavey demo:
function makeHTMLCollection(underlying) { function collection(nameOrIndex) { // I think this is how MSIE behaves: return typeof nameOrIndex === 'string' ? underlying.namedItem(nameOrIndex) : underlying.item(nameOrIndex); } collection.namedItem = function(name) { return underlying.namedItem(name); } collection.item = function(index) { return underlying.index(index); }
// define any other non-standard methods
// should use a getter here if the length can change collection.length = underlying.length;
return collection; }
You are once again missing the point: IE and (because of IE's dominance) other browsers have callable host objects for which typeof does not return "function". Changing these as you sketch above is an incompatible change that may break real web content.
There is evidence for this, because Mozilla's regexps used to report typeof-type "function" and so fell into logic wanting only a function, not a callable host object.
The resolution of that bug is clearly nonformant to ES3 section 11.4.3, as at least two commenters ('Ish' and Garrett Smith) pointed out.
On Nov 3, 2008, at 8:01 PM, David-Sarah Hopwood wrote:
Brendan Eich wrote:
On Nov 3, 2008, at 6:50 PM, David-Sarah Hopwood wrote:
That is, native objects that implement [[Call]] must be functions.
No, see 16, second list, second bullet:
"An implementation may provide additional types, values, objects, properties, and functions beyond those described in this
specification. This may cause constructs (such as looking up a variable in the
global scope) to have implementation-defined behaviour instead of throwing
an error (such as ReferenceError)."So what does "Objects that implement this internal method are called functions." in the description of [[Call]] mean, then? If it is not true for native objects (which is what the section claims to be
describing), then it is simply incorrect.
It's saying you can call anything that's callable a function, or
perhaps even loosely defining a term "function".
But this does not guarantee that typeof returns "function", that the
internal [[Class]] property has the value "Function", or that
Function.prototype is in the prototype chain, among other potentially
useful properties.
The rest of the spec doesn't usually refer to the property of being a
function without further explanation, since it is unclear which of
these things are intended.
, Maciej
Maciej Stachowiak wrote:
On Nov 3, 2008, at 11:32 AM, David-Sarah Hopwood wrote:
Mark S. Miller wrote:
First, I'd like to thank Richard Cornford, cc'ed, who provided the earlier draft of Function.prototype.bind that grew into this one. Thanks!
Below, I modified Richard's draft according to our agreements in Redmond. But I'm not happy with its complexity. If we instead specify that we test in step 3 whether the [[Class]] of G is "Function", the rest of bind() becomes much easier to specify. Should we? The only functionality lost is the ability to use bind() as a generic applied to callable non-functions. Do we care whether the built-in bind() can handle these?
We should consider simply outlawing callable nonfunctions in ES3.1.
Why is it important that callability be tied to a specific value of the [[Class]] internal property?
Specification complexity. There are quite a few places in the spec that could be simplified if only functions were callable; not just Function.prototype.bind. For example, 'IsCallable' could be removed entirely.
On Mon, Nov 3, 2008 at 7:08 PM, Brendan Eich <brendan at mozilla.com> wrote:
See also 11.4.3 The typeof Operator (second to last table row).
For reference, the last three rows of that table are
Object (native and doesn't implement [[Call]]) "object" Object (native and implements [[Call]]) "function" Object (host) Implementation-dependent
So it's pretty clear from the text you cite that typeof of a native object that implements [[Call]] must be "function".
On Mon, Nov 3, 2008 at 8:14 PM, David-Sarah Hopwood < david.hopwood at industrial-designers.co.uk> wrote:
There is evidence for this, because Mozilla's regexps used to report typeof-type "function" and so fell into logic wanting only a function, not a callable host object.
The resolution of that bug is clearly nonformant to ES3 section 11.4.3, as at least two commenters ('Ish' and Garrett Smith) pointed out.
Can someone provide a link to this bug, or to that prior discussion of this bug? Thanks.
On FF3.0.3, a bit of testing reveals that RegExp instances are indeed callable as functions, which presumably means they have an internal [[Call]] property. And they are clearly native objects, not host objects. However, unlike Rhino or WebKit, of FF3.0.3 at least, typeof of a RegExp does return "object". I don't see any way to rationalize this as conforming to the spec. Since WebKit conforms to the ES3 spec in this regard, it would seem that one can both follow this clause of the spec and not break the web.
On Mon, Nov 3, 2008 at 8:16 PM, Maciej Stachowiak <mjs at apple.com> wrote:
It's saying you can call anything that's callable a function, or perhaps even loosely defining a term "function".
But this does not guarantee that typeof returns "function", that the internal [[Class]] property has the value "Function", or that Function.prototype is in the prototype chain, among other potentially useful properties.
If F is a callable native object, then the section of the spec Brendan cites (and which FF violates) does guarantee that |typeof F| be "function". Whether we want to describe such objects as functions in prose about them is another matter. In descriptive prose, I prefer to describe as functions only native objects whose [[Class]] property is "Function".
On Nov 3, 2008, at 8:51 PM, Mark S. Miller wrote:
On Mon, Nov 3, 2008 at 7:08 PM, Brendan Eich <brendan at mozilla.com>
wrote:See also 11.4.3 The typeof Operator (second to last table row).
For reference, the last three rows of that table are
Object (native and doesn't implement [[Call]]) "object" Object (native and implements [[Call]]) "function" Object (host) Implementation- dependent
So it's pretty clear from the text you cite that typeof of a native
object that implements [[Call]] must be "function".
No, it must have typeof-type "function" -- that is not the same as
being a function object -- as having internal [[Class]] property value
"Function" (13.2 step 3).
Let's agree (I do, with your words at the end of your message) to use
"a function" to mean "a function object", that is, "an object whose
[[Class]] is ''Function''." But the typeof spec is not talking about
the value of the object's [[Class]] internal property at all.
Put another way, all function objects are callable but not all
callables are function objects.
Consider Python and many similar languages; consider too the bridging
between DOM, Java, Python, and other runtimes where callables that are
not anything like JS functions must have object reflections in JS.
Such reflection objects are not required by ES1-3 to have typeof-type
"function" and it's more useful in our experience to give them typeof-
type "object".
On FF3.0.3, a bit of testing reveals that RegExp instances are
indeed callable as functions, which presumably means they have an
internal [[Call]] property. And they are clearly native objects, not
host objects. However, unlike Rhino or WebKit, of FF3.0.3 at least,
typeof of a RegExp does return "object". I don't see any way to
rationalize this as conforming to the spec. Since WebKit conforms to
the ES3 spec in this regard, it would seem that one can both follow
this clause of the spec and not break the web.
First, this has nothing to do with whether all callables are function
objects.
Second, the reason we retreated on following ES1-3's spec for typeof
here was precisely compatibility, both Web and Mozilla platform
compatibility. See these bugs:
bugzilla.mozilla.org/show_bug.cgi?id=61911, bugzilla.mozilla.org/show_bug.cgi?id=289933
Third, the issue of whether RegExp having a [[Call]] internal property
is a good idea is separate from any of this "all callables should be
function objects" argument. Let's agree that callable regexps are a
bad idea.
Nevertheless, the ES1-3 specs allow this extension, in particular the
typeof sub-spec specifies that such callable native objects as
callable RegExp instances have typeof-type "function". We tried that,
it broke too many pages that want what other browsers do.
There were two possible fixes: removing RegExp's [[Call]] internal
property; changing how typeof works on a native object. We picked the
latter because of too much Mozilla-specific code that depended on
RegExp instances being callable. See Alex Fritze's comments in bugzilla.mozilla.org/show_bug.cgi?id=289933
.
Again, this callable regexp story is a sideshow. It's about typeof. It
is not relevant to the question of whether all callable native objects
must be function objects. Just based on the ES1-3 specs, and taking
chapter 16 of ES3 into account, it's clear that not all callable
native objects must be function objects -- objects whose [[Class]] is
"Function".
If F is a callable native object, then the section of the spec
Brendan cites (and which FF violates) does guarantee that |typeof F|
be "function". Whether we want to describe such objects as functions
in prose about them is another matter. In descriptive prose, I
prefer to describe as functions only native objects whose [[Class]]
property is "Function".
Yes, that is the definition used consistently (or nearly so) in the
spec. We should fix any deviations, and strive to use "callable" for
the general term and "function" only for objects whose [[Class]] is
"Function".
On Nov 3, 2008, at 8:01 PM, David-Sarah Hopwood wrote:
Brendan Eich wrote:
On Nov 3, 2008, at 6:50 PM, David-Sarah Hopwood wrote:
That is, native objects that implement [[Call]] must be functions.
No, see 16, second list, second bullet:
"An implementation may provide additional types, values, objects, properties, and functions beyond those described in this
specification. This may cause constructs (such as looking up a variable in the
global scope) to have implementation-defined behaviour instead of throwing
an error (such as ReferenceError)."So what does "Objects that implement this internal method are called functions." in the description of [[Call]] mean, then? If it is not true for native objects (which is what the section claims to be
describing), then it is simply incorrect.
The ECMA-262 spec has many flaws (fewer than a lot of standard
specifications I can name, but too many, still). Thanks for reminding
me about this one. It's mis-informative prose. Try not to bend the
world around it.
On Nov 3, 2008, at 8:14 PM, David-Sarah Hopwood wrote:
The resolution of that bug is clearly nonformant to ES3 section
11.4.3, as at least two commenters ('Ish' and Garrett Smith) pointed out.
Yes, that's obvious! No prize for noticing. We intentionally violated
ECMA-262 there, for the reasons I gave in reply to Mark's message: Web
- Mozilla platform compatibility. Web compatibility wants typeof /hi/
== "object". Mozilla compatibility back to 1997 or so wants /hi/ ("...hi.") to call exec and return ["hi"].
We'll make regexps non-callable in a future release whose numbering
allows us to break compatibility for all the users who may be relying
on this JS extension.
On Nov 3, 2008, at 8:51 PM, Mark S. Miller wrote:
On FF3.0.3, a bit of testing reveals that RegExp instances are
indeed callable as functions, which presumably means they have an
internal [[Call]] property. And they are clearly native objects, not
host objects. However, unlike Rhino or WebKit, of FF3.0.3 at least,
typeof of a RegExp does return "object". I don't see any way to
rationalize this as conforming to the spec. Since WebKit conforms to
the ES3 spec in this regard, it would seem that one can both follow
this clause of the spec and not break the web.
JavaScriptCore's RegExp objects have been callable since Safari 1.0
Beta 1 and I believe they have returned "function" from typeof that
whole time. (The Mozilla bug report says otherwise but I think that
testing must have been in error.) I'm not aware of any compatibility
issues due to either the callable extension or the way typeof is
reported as a result. I'm also not specifically aware of a
compatibility need for the callable regexp extension; it seems to be
something we inherited when we forked from KJS/KHTML many years ago.
, Maciej
On Nov 3, 2008, at 10:26 PM, Maciej Stachowiak wrote:
JavaScriptCore's RegExp objects have been callable since Safari 1.0
Beta 1 and I believe they have returned "function" from typeof that
whole time. (The Mozilla bug report says otherwise but I think that
testing must have been in error.)
Another report from 2005 testifies to the same result (typeof /hi/ ==
"object" in Safari):
bugzilla.mozilla.org/show_bug.cgi?id=289933#c5
Could also be in error, but is it possible that back then the result
was different?
I'm not aware of any compatibility issues due to either the callable
extension
Agreed, the only "compatibility" issue with callable regexps is that
some people read ECMA-262, the typeof sub-spec, and ask us to make
typeof /hi/ == "function", while others compare that to IE (and
Netscape 4, FWIW) and ask for "object".
or the way typeof is reported as a result.
The typeof /hi/ == "function" result is considered broken by people
developing against other browsers, trying to separate function objects
from other kinds of objects, not caring about callable non-function
objects.
On Nov 3, 2008, at 10:39 PM, Brendan Eich wrote:
On Nov 3, 2008, at 10:26 PM, Maciej Stachowiak wrote:
JavaScriptCore's RegExp objects have been callable since Safari 1.0
Beta 1 and I believe they have returned "function" from typeof that
whole time. (The Mozilla bug report says otherwise but I think that
testing must have been in error.)Another report from 2005 testifies to the same result (typeof /hi/
== "object" in Safari):bugzilla.mozilla.org/show_bug.cgi?id=289933#c5
Could also be in error, but is it possible that back then the result
was different?
I checked out the code from 2002, and it looks like it would return
"function", but thanks to the Apple DevTools team's love of
incompatible build file format changes, I can't easily build to verify.
I'm not aware of any compatibility issues due to either the
callable extensionAgreed, the only "compatibility" issue with callable regexps is that
some people read ECMA-262, the typeof sub-spec, and ask us to make
typeof /hi/ == "function", while others compare that to IE (and
Netscape 4, FWIW) and ask for "object".or the way typeof is reported as a result.
The typeof /hi/ == "function" result is considered broken by people
developing against other browsers, trying to separate function
objects from other kinds of objects, not caring about callable non- function objects.
I'm sure people may have an opinion one way or the other, I just don't
know of any Web content actually broken by this in practice. I don't
have strong feelings on the matter in either direction, just reporting
our experience.
, Maciej
Mark S. Miller wrote:
On Mon, Nov 3, 2008 at 7:08 PM, Brendan Eich <brendan at mozilla.com> wrote:
See also 11.4.3 The typeof Operator (second to last table row).
For reference, the last three rows of that table are
Object (native and doesn't implement [[Call]]) "object" Object (native and implements [[Call]]) "function" Object (host) Implementation-dependent
So it's pretty clear from the text you cite that typeof of a native object that implements [[Call]] must be "function".
On Mon, Nov 3, 2008 at 8:14 PM, David-Sarah Hopwood < david.hopwood at industrial-designers.co.uk> wrote:
Brendan Eich wrote:
There is evidence for this, because Mozilla's regexps used to report typeof-type "function" and so fell into logic wanting only a function, not a callable host object. The resolution of that bug is clearly nonformant to ES3 section 11.4.3, as at least two commenters ('Ish' and Garrett Smith) pointed out.
Can someone provide a link to this bug, or to that prior discussion of this bug? Thanks.
Sorry, I meant to post that before.
The bug that Brendan and I were referring to was 61911: bugzilla.mozilla.org/show_bug.cgi?id=61911
Also see bugs.ecmascript.org/ticket/251, but the discussion
there appears to be making ES4-specific assumptions. (It is also quite confused when referring to ES3: Opera and MSIE's behaviour is correct according to the spec, but that is because they don't have callable regexps.)
On FF3.0.3, a bit of testing reveals that RegExp instances are indeed callable as functions, which presumably means they have an internal [[Call]] property. And they are clearly native objects, not host objects. However, unlike Rhino or WebKit, of FF3.0.3 at least, typeof of a RegExp does return "object". I don't see any way to rationalize this as conforming to the spec.
I agree; that's the same reasoning I was using.
Note that in the comments of bug 61911, Brendan used the argument that regexp objects were proposed to be callable in ES4, but that is presumably back up for discussion in Harmony. I would recommend against it: callable regexps were a SpiderMonkey extension never adopted by any non-Mozilla JavaScript implementation AFAIK, and they introduce an irregularity in the language.
Brendan Eich wrote:
On Nov 3, 2008, at 8:14 PM, David-Sarah Hopwood wrote:
The resolution of that bug is clearly nonformant to ES3 section 11.4.3, as at least two commenters ('Ish' and Garrett Smith) pointed out.
Yes, that's obvious! No prize for noticing. We intentionally violated ECMA-262 there, for the reasons I gave in reply to Mark's message: Web + Mozilla platform compatibility. Web compatibility wants typeof /hi/ == "object". Mozilla compatibility back to 1997 or so wants /hi/("...hi.") to call exec and return ["hi"].
We'll make regexps non-callable in a future release whose numbering allows us to break compatibility for all the users who may be relying on this JS extension.
What's wrong with that release being the one that first supports ES3.1 (so that in ES3.1, native objects are callable iff they are functions)?
There will be other minor incompatibilities that are required by ES3.1, so it seems as though that release will have to be one "whose numbering allows [you] to break compatibility".
David-Sarah Hopwood wrote:
Note that in the comments of bug 61911, Brendan used the argument that regexp objects were proposed to be callable in ES4, but that is presumably back up for discussion in Harmony. I would recommend against it: callable regexps were a SpiderMonkey extension never adopted by any non-Mozilla JavaScript implementation AFAIK,
I wasn't aware when I wrote this that JavaScriptCore supports them. But in that regard, Maciej Stachowiak wrote:
I'm also not specifically aware of a compatibility need for the callable
regexp extension; it seems to be something we inherited when we forked
from KJS/KHTML many years ago.
Mark S. Millerwrote:
<snip> Below, I modified Richard's draft according to our agreementsin Redmond. But I'm not happy with its complexity. If we instead specify that we test in step 3 whether the [[Class]] of G is "Function", the rest of bind() becomes much easier to specify. Should we? The only functionality lost is the ability to use bind() as a generic applied to callable non-functions. Do we care whether the built-in bind() can handle these?
My motivation for using IsCallable was influenced by the position of - bind - in the language, alongside - call - and - apply - as properties of - Function.prototype -. It seemed a reasonable starting position that - bind - should be applicable to exactly the same set of object as - apply - and - call -, and those two both use the condition "If the object does not have a [[Call]] property, a TypeError exception is thrown" (in ES3 and the current ES3.1 draft). Where "If IsCallable(G) is false, throw a TypeError exception" is effectively the same condition based on the current definition of IsCallable.
It might be argued that letting - call - and - apply - act on callable host objects was a specification error in the previous language versions. And that while back-compatibility would suggest not changing - call - and - apply -, any new method should not repeat that 'error'.
Looking at the other uses of IsCallable in the current draft, and wondering how (and if) they may be exposed to callable host objects, I observed:-
Section 11.2.3 "Function Calls", where it is imperative that callable host objects pass the IsCallable test (else they cannot be called and the language becomes non-viable for scripting hosts). Because the specification is in terms of "an implementation must behave as if ... " the implication of this section is that if a host object is callable it must behave as if it has a [[Call]] method, so that all callable host object can return true from IsCallable. Thus, there is effectively no such thing as a host object that can be called that does not have a [[Call]] method, in terms of the specification.
Section 8.10.5 "ToPropertyDescriptor ( Desc )", where it may be a bit convoluted but does look like callable host objects can be the subjects of steps 13.b and 15.b in the algorithm. And where it might be argued that allowing such a thing would not be a good idea.
If I have not missed something (a possibility) the formulation would be along the lines of:-
Object.defineProperty ( obj, 'someProperty', { get 'getter'(){return callableHostObject1;}, get 'setter'(){return callableHostObject2;} } );
- leaving - obj.someProperty - with callable host objects as its getter and setter. (This also makes me wonder to what degree it will be possible for implementations to optimise away the implied runtime creation of objects resulting from object literals used to define the property descriptor for used with - Object.defineProperty -, as the value resulting from the scope chain lookup of - callableHostObject1 - cannot easily be determined (if at all) when the code is complied.)
The remaining uses of IsCallable are in various toJSON methods and in some of the new methods added to the Array.prototype. It would be easy for these IsCallable uses to be applied to callable host objects.
It looks like the easiest clarification of this situation would be to remove the use of IsCallable from section 11.2.3 and re-define IsCallable so that it only returns true if the object is a native ECMAScript object and has a [[Call]] method (maybe; and has a [[Class]] of "Function"). (Assuming that there is a general desire to prevent - bind - from acting on callable host objects and prevent them from being getters and setters).
15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, ...]]) <snip> 3. If IsCallable(G) is false, throw a TypeError exception. 4. Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.
In retrospect, I am dissatisfied with the wording of that step. It may be possible for it to be interpreted as meaning the arguments following all of "thisArg (arg1, arg2 etc)" are the ones to be included in the list. Rewording it to: "Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (that is; arg1, arg2 etc), in order." should avoid that ambiguity.
<snip>
15.3.4.5.1 [[Call]] Algorithm for the [[Call]] method of a function F returned from the bind method: When executed with zero or more arguments, F uses the values of T, G and A that were associated with it at its creation, <snip>
The algorithm for the - bind - method no longer explicitly requires the association of T, G and A with F, so invoking that association at this point seems a bit odd.
Richard Cornford.
On Nov 4, 2008, at 10:43 AM, David-Sarah Hopwood wrote:
Can someone provide a link to this bug, or to that prior discussion
of this bug? Thanks.Sorry, I meant to post that before.
The bug that Brendan and I were referring to was 61911: bugzilla.mozilla.org/show_bug.cgi?id=61911
If you caught up on the thread, you saw that I also cited this bug:
bugzilla.mozilla.org/show_bug.cgi?id=289933
Comment 10 complains about the incompatible change from typeof /hi/ ==
"object" to "function".
A dup of 61911 is
bugzilla.mozilla.org/show_bug.cgi?id=353448
wherein Ish also testifies that Safari (among others) returns "object"
as regexp instance typeof.
Also see bugs.ecmascript.org/ticket/251, but the discussion there appears to be making ES4-specific assumptions. (It is also quite confused when referring to ES3: Opera and MSIE's behaviour is correct according to the spec, but that is because they don't have callable regexps.)
You're right, I'm not sure why I thought otherwise.
On FF3.0.3, a bit of testing reveals that RegExp instances are indeed callable as functions, which presumably means they have an internal
[[Call]] property. And they are clearly native objects, not host objects.
However, unlike Rhino or WebKit, of FF3.0.3 at least, typeof of a RegExp
does return "object". I don't see any way to rationalize this as conforming to
the spec.I agree; that's the same reasoning I was using.
Note that in the comments of bug 61911, Brendan used the argument that regexp objects were proposed to be callable in ES4, but that is
presumably back up for discussion in Harmony.
It was withdrawn from ES4 before this summer and the Oslo meeting. See
spreadsheets.google.com/pub?key=pFIHldY_CkszsFxMkQOReAQ&gid=2
the row whose first cell contains "/regexp/('test')".
I would recommend against it: callable regexps were a SpiderMonkey extension never adopted by any non-Mozilla JavaScript implementation AFAIK,
Thread catchup needed re: Safari JavaScriptCore / KJS, but I still
wonder why so many testified around 2005 that Safari returned "object"
as regexp typeof.
and they introduce an irregularity in the language.
Agreed.
On Nov 4, 2008, at 10:52 AM, David-Sarah Hopwood wrote:
Brendan Eich wrote:
We'll make regexps non-callable in a future release whose numbering allows us to break compatibility for all the users who may be
relying on this JS extension.What's wrong with that release being the one that first supports ES3.1 (so that in ES3.1, native objects are callable iff they are
functions)?
Maybe. Let's finish ES3.1 first.
There will be other minor incompatibilities that are required by
ES3.1, so it seems as though that release will have to be one "whose
numbering allows [you] to break compatibility".
Where are the ES3.1 incompatibilities vs. ES3 summarized?
Brendan Eich wrote:
On Nov 4, 2008, at 10:52 AM, David-Sarah Hopwood wrote:
Brendan Eich wrote:
We'll make regexps non-callable in a future release whose numbering allows us to break compatibility for all the users who may be relying on this JS extension.
What's wrong with that release being the one that first supports ES3.1 (so that in ES3.1, native objects are callable iff they are functions)?
Maybe. Let's finish ES3.1 first.
You can always remove callable regexps before ES3.1; my point was that at least one technically incompatible release will be needed in order to support ES3.1.
There will be other minor incompatibilities that are required by ES3.1, so it seems as though that release will have to be one "whose numbering allows [you] to break compatibility".
Where are the ES3.1 incompatibilities vs. ES3 summarized?
Annexes D and E of the Kona draft.
Also, any addition of a property (of one of the built-in objects) or a global (such as 'JSON') is a theoretical incompatibility, since it would have been possible to write code that depended on the non-existance of that property or global.
Note that appendices C, D, and E are not particularly complete or up to date. This is something we are going to try to work on between now and Kona as I believe that these summaries are very important to understanding the overall impact of ES3.1
On Nov 6, 2008, at 5:11 PM, David-Sarah Hopwood wrote:
Brendan Eich wrote:
On Nov 4, 2008, at 10:52 AM, David-Sarah Hopwood wrote:
Brendan Eich wrote:
We'll make regexps non-callable in a future release whose numbering allows us to break compatibility for all the users who may be
relying on this JS extension.What's wrong with that release being the one that first supports
ES3.1 (so that in ES3.1, native objects are callable iff they are
functions)?Maybe. Let's finish ES3.1 first.
You can always remove callable regexps before ES3.1; my point was that at least one technically incompatible release will be needed in order to support ES3.1.
So what? "Technically incompatible" as you use it refers to a number
of concessions to reality in ES3.1, breaking compatibility with parts
of ES1-3 that were never implemented. Or else to ES3.1 adding property
names in standard objects, which is not comparable to changing or
removing something like callable regexps.
Removing callable regexps breaks Mozilla- and/or Safari/KHTML-specific
code that invokes regexps, with fail-stop exceptions. Speaking for
Mozilla, we would rather not make the major-version-number change I
mentioned (cited above) solely for ES3.1 -- we have a few other APIs
to break.
But that's our business, no need to argue about it here.
What we should argue about is how much ES3.1 might actually break (not
in theory, and not based on paper differences with ES1-3 where no
browser implemented what ES1-3 specified).
Adding ES3.1 Object.* extensions is not likely to break anything.
JSON is another issue.
Removing ES3 syntax or semantics from ES3.1 in the default (non-
strict) mode is suspect. Anything in the latest ES3.1 drafts that
removes spec-parts outright should be reviewed carefully.
Certain changes to semantics (e.g. Date.parse preferring ISO 8601)
that improve interoperation, compared to the current implementation-
defined ES1-3 spec and browser reality, are experiments that we've
already agreed to try, with mandatory implementation and testing
against the web before spec finalization.
Annexes D and E of the Kona draft.
Thanks, I am reading. We've been over all of these points many times,
in ES4 and ES3.1 contexts on the lists and in committee.
But again, the Annex D items provoke a "so what?" reaction. These
items (memoized standard constructors/prototypes, order of evaluation
bugs in ES1, RegExp.prototype being a RegExp instance) are not even
incompatibilities against "reality", meaning what most or all browser
implementations do.
Annex E starts with format-control char non-stripping and BOMs-as-
whitespace, and for (x in null) or for (x in undefined) not throwing.
Again: reality (and nothing like removing a long-standing
implementation extension).
The RegExp literal evaluation change will fix an ES3 bug (we have the
bug reports; see bugzilla.mozilla.org/show_bug.cgi?id=98409
and its dups). We will give it a try some time in the first half of
next year, in a Firefox pre-release.
The last three items in Annex E may be problematic. They are not
implemented by any browser, AFAIK.
Also, any addition of a property (of one of the built-in objects) or a global (such as 'JSON') is a theoretical incompatibility, since it
would have been possible to write code that depended on the non-existance of that property or global.
Yes, I know. This is not just theoretical in connection to ES3.1.
Facebook has (had, I hope) a JSON codec that started like so:
if(!this.JSON){ JSON=function(){function f(n){return n<10?'0'+n:n;} Date.prototype.toJSON=function(){return this.getUTCFullYear()+'-'+ . . . }
Unfortunately it was not based on json2.js -- its methods were named
Encode and Decode. Hard failure in an ES3.1-supporting browser.
IE8 beta 2 and Firefox 3.1 betas have JSON, so at least two vendors
are taking the costs for this incompatible change now. We do not have
time or risk tolerance to take on more, speaking for Firefox, given
the unfinished ES3.1 spec.
A given non-syntactic extension is one of
- a new global property;
- a new prototype property;
- a new constructor property.
TC39 has generally avoided adding new globals; JSON is "it" for ES3.1
(AFAIK), and since Murphy was an optimist, it is breaking some extant
content.
A new Object.prototype property shows up as a global property and may
break object-detecting scripts, so that's out. Of course, 3.1 extends
ES3's Array.prototype methods based on reality, and adds toJSON to
other non-Object prototypes. The reality-based precedents that give us
hope we can get away with these are browser implementations of the
Array extras, and common Ajax usage of JSON codecs that probe for
toJSON.
But yes: JSON is already breaking code.
By comparison, extending constructors is pretty safe based on
experience so far. We've done it in past releases for Array and String
"static generics", e.g. Array.slice(arraylike, start, end).
The main issue for ES3.1 is to get to the "candidate recommendation"
degree of spec completeness, where implementations can support 3.1 and
attempt to evangelize authors of the few web pages or apps that might
be bothered by the changes in 3.1.
If we get there soon, great -- but that does not mean we will roll to
"Mozilla 2" just for that reason, or remove callable regexps at the
same time. Removing is a bigger compatibility risk than adding.
-----Original Message----- From: es3.x-discuss-bounces at mozilla.org [mailto:es3.x-discuss- bounces at mozilla.org] On Behalf Of Brendan Eich Sent: Thursday, November 06, 2008 8:05 PM
...
TC39 has generally avoided adding new globals; JSON is "it" for ES3.1 (AFAIK), and since Murphy was an optimist, it is breaking some extant content.
Actually, Decimal would be another...
On Nov 6, 2008, at 9:58 PM, Allen Wirfs-Brock wrote:
-----Original Message----- From: es3.x-discuss-bounces at mozilla.org [mailto:es3.x-discuss- bounces at mozilla.org] On Behalf Of Brendan Eich Sent: Thursday, November 06, 2008 8:05 PM
...
TC39 has generally avoided adding new globals; JSON is "it" for ES3.1 (AFAIK), and since Murphy was an optimist, it is breaking some extant content.
Actually, Decimal would be another...
Good point. But Decimal is not listed in "15.1.4 Constructor
Properties of the Global Object".
I just searched for Decimal and ToDecimal in the latest 3. 1 draft,
and it does not hang together. Nowhere in chapter 9 is the Decimal
type defined or broken out, but 4.3.3 says that Decimal is a type,
while 4.3.4 says "A Decimal object is a member of the type Object and
is an instance of the built-in Number object." 15.13 contradicts this.
The use of "decimal representation" in 15.7 to mean arbitrary
precision decimal is confusing.
Agreed, I believe that the current intent (Sam??) is for decimal to be implemented as a complete parallel to Number with a distinct primitive value type, an wrapper constructor that creates objects with a distinct [[Class]] value, appropriate conversion functions, etc. However, this still this doesn't appear to be fully realized in the current draft.
In addition to the problems areas Brendan pointed out, all the operators defined in section 11 continue to show confusion between primitive decimal values and decimal wrapper objects and decimal is not integrated into the ToPrimitive/[[DefaultValue]]/hint mechanisms of the specification.
Mark S. Miller wrote:
11. If the [[Class]] property of /G/ is *"Function"*, then 1. Get the *length* property of /G/. 2. Let /L/ be Result(11a) minus the length of /A/.
What does "minus" mean here? Result(11a) could be anything.
Waldemar
On Mon, Nov 10, 2008 at 4:48 PM, Waldemar Horwat <waldemar at google.com>wrote:
Mark S. Miller wrote:
11. If the [[Class]] property of /G/ is *"Function"*, then 1. Get the *length* property of /G/. 2. Let /L/ be Result(11a) minus the length of /A/.
What does "minus" mean here? Result(11a) could be anything.
Since this is conditional on the [[Class]] of G being "Function", doesn't that mean the length is created as a non-configurable readonly number property when G is created?
Step 7 of 13.2 says:
- Set the length property of F to the number of formal parameters specified in FormalParameterList. If no parameters are specified, set the length property of F to 0. This property is given attributes as specified in 15.3.5.1.
there it says:
15.3.5 Properties of Function Instances In addition to the required internal properties, every function instance has a [[Call]] property, a [[Construct]] property and a [[Scope]] property (see 8.6.2 and 13.2). The value of the [[Class]] property is "Function". 15.3.5.1 length The value of the length property is an integer that indicates the "typical" number of arguments expected by the function. However, the language permits the function to be invoked with some other number of arguments. The behaviour of a function when invoked on a number of arguments other than the number specified by its length property depends on the function. This property has the attributes { [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }.
Waldemar Horwat wrote:
Mark S. Miller wrote: [Kona 15.3.4.5]
11. If the [[Class]] property of /G/ is *"Function"*, then 1. Get the *length* property of /G/. 2. Let /L/ be Result(11a) minus the length of /A/.
[These substeps are actually labelled a. and b.]
What does "minus" mean here? Result(11a) could be anything.
The 'length' property of a built-in object with [[Class]] "Function" is not Writable or Configurable [Kona 15.3.5.1], so it must be equal to the number it was set to in either [Kona 13.2 step 7] or [Kona 15.3.4.5 step 11c or 12], which are the only places where built-in objects of [[Class]] "Function" are created (and [[Class]] cannot be changed after creation). But that should be explained in a NOTE section.
Caveat: [section 15]
The value of the [[Class]] property of a host object may be any value,
even a value used by a built-in object for its [[Class]] property.
So any random host object might have [[Class]] "Function" (which is a bug). If that is the case, all bets are off (and in that case steps 11 and 15 of the 'bind' algorithm are broken anyway -- for example, the 'length' or 'prototype' properties of G might not exist).
Incidentally, the following sentence in section 15:
Unless specified otherwise, the [[Class]] property of a built-in
object is "Function" if that built-in object has a [[Call]]
property [...]
is misleading because:
The value of the [[Class]] property is defined by this specification
for every kind of built-in object.
i.e. there is no default for [[Class]] in the case of built-in objects. That is what allowed me to make the above assertions for built-in objects, otherwise I'd have had to read the entire spec rather than just searching for "Function". The sentence that implies that there are defaults for [[Class]] should be removed.
Mark S. Miller wrote:
On Mon, Nov 10, 2008 at 4:48 PM, Waldemar Horwat <waldemar at google.com> wrote:
Mark S. Miller wrote:
11. If the [[Class]] property of /G/ is *"Function"*, then 1. Get the *length* property of /G/. 2. Let /L/ be Result(11a) minus the length of /A/.
What does "minus" mean here? Result(11a) could be anything.
Since this is conditional on the [[Class]] of G being "Function", doesn't that mean the length is created as a non-configurable readonly number property when G is created?
See my other reply. Yes for built-in objects; no for host objects, because of:
The value of the [[Class]] property of a host object may be any value,
even a value used by a built-in object for its [[Class]] property.
In general I think that the internal properties of host objects are hopelessly underspecified. (That's partly why Jacaranda, ADsafe, and Cajita have to depend on no host objects being reachable from subset code.)
Step 7 of 13.2 says:
- Set the length property of F to the number of formal parameters specified in FormalParameterList. If no parameters are specified, set the length property of F to 0. This property is given attributes as specified in 15.3.5.1.
The argument also has to depend
David-Sarah Hopwood wrote:
Waldemar Horwat wrote:
Mark S. Miller wrote: [Kona 15.3.4.5]
11. If the [[Class]] property of /G/ is *"Function"*, then 1. Get the *length* property of /G/. 2. Let /L/ be Result(11a) minus the length of /A/.
[These substeps are actually labelled a. and b.]
What does "minus" mean here? Result(11a) could be anything.
The 'length' property of a built-in object with [[Class]] "Function" is not Writable or Configurable [Kona 15.3.5.1], so it must be equal to the number it was set to in either [Kona 13.2 step 7] or [Kona 15.3.4.5 step 11c or 12], which are the only places where built-in objects of [[Class]] "Function" are created (and [[Class]] cannot be changed after creation).
Also the value set in [Kona 13.2 step 7] or [Kona 15.3.4.5 step 11c or 12] is in the range 0..(maximum number of function arguments).
However, I cannot find anything in the spec that allows an implementation to fail to support an unbounded number of arguments to a function. This is a bug, probably in section 10.1.3. There are other similar bugs, for example the length of array literals may be unbounded.
In general, there is no permission to fail when the spec requires computing a number that is not representable as a value of Number type, or when the implementation runs out of memory, or reaches a maximum stack depth or other implementation limit. This should be fixed in ES3.1 (note that all of the secure subsets would like to be able to trap such failures and shut down the entire context, as opposed to throwing an exception).
First, I'd like to thank Richard Cornford, cc'ed, who provided the earlier draft of Function.prototype.bind that grew into this one. Thanks!
Below, I modified Richard's draft according to our agreements in Redmond. But I'm not happy with its complexity. If we instead specify that we test in step 3 whether the [[Class]] of G is "Function", the rest of bind() becomes much easier to specify. Should we? The only functionality lost is the ability to use bind() as a generic applied to callable non-functions. Do we care whether the built-in bind() can handle these?
15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, …]]) The bind method takes one or more arguments, thisArg and (optionally) arg1, arg2, etc, and returns a new function object by performing the following steps:
15.3.4.5.1 [[Call]] Algorithm for the [[Call]] method of a function F returned from the bind method: When executed with zero or more arguments, F uses the values of T, G and A that were associated with it at its creation, and the following steps are taken:
15.3.4.5.2 [[Construct]] Algorithm for the [[Construct]] method of a function F returned from the bind method: When executed with zero or more arguments, F uses the values of G and A that were associated with it at its creation, and the following steps are taken: