Function.prototype.bind

Brendan Eich brendan at mozilla.org
Wed Sep 10 18:33:51 PDT 2008


On Sep 10, 2008, at 5:37 PM, David-Sarah Hopwood wrote:

> Brendan Eich wrote:
>> On Sep 10, 2008, at 10:15 AM, David-Sarah Hopwood wrote:
>>
>>> However, unlike what I proposed, 'strawman:lexical_scope' doesn't  
>>> make
>>> the bindings of the primordials that are visible when it is active
>>> deeply immutable. I suppose that's difficult if you want the
>>> prototypes to appear to be the same between code that is in such a
>>> block and code that is not -- for instance, '"" instanceof String'
>>> should work whether or not 'String' refers to a deeply immutable or
>>> mutable constructor.
>>
>> Right. Also, people mutate standard objects, whether it's a good  
>> idea in
>> the large or not. The "use lexical scope" idea is not meant to break
>> compatibility on that point.
>>
>> It's rarer (although still done -- see
> [https://bugzilla.mozilla.org/show_bug.cgi?id=409252#c4])
>> for web JS to mutate the global bindings for Object, Date, etc.
>
> ECMA-262 is entirely unclear about what effects that is supposed to  
> have,

Or where the language is clear, it is not consistent:

http://wiki.ecmascript.org/doku.php?id=clarification:which_prototype


> and it did different things between implementations (for example  
> FF2 used
> shallow binding of at least Array,

What do you mean by "shallow binding"?


> while IE7 mostly ignored changes to
> these bindings). So if there is any code relying on doing this, at  
> best
> it worked by accident.

But it does work, and that's why we couldn't change it for Firefox 3.  
Joel Spolsky would have our heads.


> I see only references to rebinding of 'Date' in that bug report (and
> 'Namespace' which is not relevant to ES3.1).

Namespace is from ECMA-357, E4X. It's relevant because we do not want  
to special-case the constructor binding rules per standard object. We  
want one rule to bind them all, partly for simplicity of  
implementation, mostly for cognitive simplicity for programmers using  
JS, and anyway to avoid borrowing compatibility trouble (more below,  
where you propose borrowing more than your net worth :-/).

You have not looked at all the regressions from the original bug:

https://bugzilla.mozilla.org/show_bug.cgi?id=376957

listed in the "Depends on:" row of links.

https://bugzilla.mozilla.org/show_bug.cgi?id=407323 (XML, ECMA-357).
https://bugzilla.mozilla.org/show_bug.cgi?id=407727 (let Object, same  
as var Object)
https://bugzilla.mozilla.org/show_bug.cgi?id=407957 (Iterator,  
similar to Namespace)

and the big one, bigger even than fogbuz (sorry, Joel):

https://bugzilla.mozilla.org/show_bug.cgi?id=412324 (Error)

An old MSN compat.js file also rebinds Error unconditionally. I'm not  
sure it is used any longer, but it's still up:

http://stj.msn.com/br/gbl/js/3/mozcompat.js


> The semantics of rebinding
> Date are much clearer than they are for constructors that are  
> implicitly
> accessed as a result of evaluating literals (Array, Function, Object,
> String and RegExp). In particular, there are intractable bootstrapping
> issues in specifying what it should mean to rebind 'Object' or  
> 'Function',
> at least. Furthermore, allowing rebinding of these implicitly accessed
> constructors could inhibit useful optimizations, while I assume no-one
> really cares about optimizing Date.

Without literal syntax, you are right as far as optimization goes.  
Integrity is another issue, I don't need to tell you!

Error and its subtypes have no literal syntax, but are constructed by  
the runtime and thrown. ES3 says (e.g. 15.1.2.1 step 2) "throw a  
*SyntaxError* exception", and this is taken to mean construct an  
instance without reflecting on the current binding of SyntaxError,  
rather use a memoized prototype and internal [[Class]], etc.


> So here is my strawman proposal:
>  - leave 'Date' Writable in the global scope;
>  - make Array, Function, Object, String and RegExp non-Writable and
>    non-Configurable, unconditionally;

No; https://bugzilla.mozilla.org/show_bug.cgi?id=412324 is just a  
taste of what you'll get in the way of bug reports, I predict. I'll  
bet real money on this.


>  - make Array, Function, Object, String and RegExp not declarable as
>    variable names;
>  - make all of the new "static" methods on Array, Function, Object
>    and String non-Writable and non-Configurable, unconditionally.

I think you are missing a few classes (e.g. Error).

Having such complicated rules also seems bad. There will be more  
built-in classes. And what about "host constructors" like Image,  
Option, HTMLDivElement, etc.? Why should they have different binding  
rules?


> This will not break Ajax library code that tries to install compatible
> implementations of these new methods, because:
>
>  - if that code is running in non-strict mode, the attempted updates
>    will be silently ignored.

See https://bugzilla.mozilla.org/show_bug.cgi?id=412324 -- silent  
failure to update a ReadOnly property still breaks things.


>  - if it is running in strict mode, then it must be new code that
>    knows to catch the resulting exception.
>
> Note that the Array, Function, Object, String and RegExp constructors
> would not be sealed, and the prototypes would still be mutable. So  
> this
> proposal is not attempting to address the secure sublanguage issues
> (at least not on its own), only the issue with self-hosting.

Self-hosting is a specification and potentially an implementation  
detail, not a reason for incompatible change that we could not ship  
in Firefox 3. Good luck getting any other browser, including IE9 (in  
two years?) to do likewise.


> With this design, it's no longer necessary to worry about rebinding
> or shadowing in the self-hosting specifications, *or* in the  
> expansions
> of new syntactic sugar, provided that they only use the static methods
> and do not use Date.

Sorry, you're mistaken. The self-hosted Date needs to refer to its  
own original binding and properties. Etc.


> I do not believe that anything important on the web

I don't know what to make of this. You're wrong, and I cited evidence  
to the contrary. But feel free to start a new browser project, break  
compatibility, grow your market share, and prove me wrong.


> will break as a result of these changes -- and if it does, then I  
> think
> it desperately needed to be broken as soon as possible.

This is wrong in at least six dimensions. You are not god-emperor of  
the web. The web is more like the boss of you. You must woo it, win  
it over with better ways to do things currently done via bad old APIs  
today, before you can remove those APIs and force your will on it.

Anyway, that's my free advice, and I've been at this game for a long  
time (and we've won market share back from near 0 with Firefox -- but  
not by breaking compatibility! On the contrary, we've had to add IE  
compatibility over time, e.g. document.all -- the game theory here is  
not hard to figure out).


> The self-hosting specification of Function.prototype.bind would be:
>
>   Object.defineProperty(Function.prototype, 'bind', {
>     writable: false, enumerable: false, configurable: false, value:
>     function(self, var_args) {
>       const thisFunc = this;
>       const leftArgs = Array.slice(arguments, 1);
>       return function(var_args) {
>         const args = Array.concat(leftArgs, Array.slice(arguments,  
> 0));
>         return Function.staticApply(thisFunc, self, args);
>       };
>     }
>   });
>
> (no 'use lexical scope' needed).

Let's see a Date method or three.


>> Could you suggest a new name for Function.apply (and the static  
>> bind and
>> call, for that matter)? Thanks,
>
> I suggested apply3 and call3 in a previous post, but on second
> thoughts I'd like to change that to staticApply, staticCall and
> staticBind. The '3' doesn't work for call or bind because they take
> variable arguments, and it's ugly even for apply.

Numbered methods look like versionitis; static is better but less  
clear about meaning than generic (that these are "static methods",  
i.e., function-valued properties of the constructor, is less  
significant than that they work on all callables).

/be



More information about the Es-discuss mailing list