Draft of Function.prototype.bind.

Richard Cornford Richard at litotes.demon.co.uk
Tue Nov 4 15:05:35 PST 2008

Mark S. Millerwrote:
> 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

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 (
        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).

>    Function.prototype.bind (thisArg [, arg1 [, arg2, ...]])
> 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.

>     [[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,

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.

More information about the Es-discuss mailing list