Coercing 'this' (was: Topic list - pending changes and issues for the ES3.1 spec)

Brendan Eich brendan at mozilla.org
Mon Sep 15 18:16:18 PDT 2008


On Sep 16, 2008, at 1:54 AM, Mark S. Miller wrote:

> var funnyObj = {method: Date}
> funnyObj.method(2008,9,11)
>
> would bind funnyObj to |this| in Date, which would flow into the  
> constructor-case code as the new Date object to initialize.
>
> Agreed that thsi proposal does not prevent this existing confusion.  
> Neither does it make it worse. If there's something we can  
> plausibly do to fix this, I'd love to! Any suggestions?

Not right now. Such a self-hosted Date could use instanceof to test a  
|this| that was not undefined, and construct only if |this instanceof  
Date| -- but it still act as a re-initializer of called on an  
existing Date instance, e.g. d = new Date(2008,9,1); Date(d) -- still  
not per-spec, but this is a problem for later.


> This is also badly incompatible. Global functions are used as  
> methods of their window objects. Calling them via this.func() or  
> otherFrame.func() works, but so do calls to func() from the same  
> window.
>
> Since there's only one window per JS global object (obviously,  
> since they're the same object), all the methods of the window could  
> already be bound to their window,

You're proposing to bind |this| to all window functions in strict mode?


> and so not care what their 'this' is. However, that would break  
> code such as 'window1.func.call(window2)'. Currently, I expect func  
> will operate on window2; but if func is already bound to window1 it  
> will still operate on window1. Is this change of behavior a problem?

It could be; if you're talking about strict mode, it is yet another  
migration tax hike, and a bit of an unwarranted extra complexity to  
strict mode. What other this-binding does strict mode imply? I don't  
remember anything like this.


>> I agree. I propose that primitive 'this' values not
>> be coerced at all.
>
> This is a pretty big incompatibility. I'll scan some Ajax libraries  
> to look for obvious breaks. I suspect they'll be easy to find.
>
> Any results?

No, I'm traveling and short on time and access. Maybe some of the  
Prototype, Dojo, MochiKit, or JQuery folks on the list could help me  
out and comment.


> If the answer is that we can't avoid wrapping unconditionally, then  
> I propose that we wrap only on entry to non-strict functions, where  
> this wrapping is again cetralized in the spec to section 11.1.1.  
> Elsewhere you've written "more carrots, less sticks", with which I  
> heartily agree. If "strict" suppresses non-stratified reflection  
> that prevents many useful optimizations (with, delete <var>

(what about delete <var>? That it returns false should not prevent  
optimizations...)


> , arguments.caller, Function.caller, Function.arguments) and  
> removes pointless and costly wrapping,

Implements avoid wrapping, but sure: at some cost to implementation  
complexity. Relieving that cost in strict mode does not remove the  
complexity, though -- the default mode still requires (only for  
interpreted functions, albeit lazy if the function mentions |this| or  
|eval|) primitive-this wrapping.


> then the common wisdom may become "Make your program work under  
> strict mode so it'll be faster."

Quality implementations won't get any faster.

I'm not sure what we are saving here. The point of strict mode is to  
prevent bad practices and pitfalls, but adding scripted functions as  
methods of standard prototypes, or otherwise arranging to call  
methods on primitives, is not bad practice in my book. It's good  
enough for s.charAt(i), why not for s.myCustomStringMethod()? One of  
the use-cases for the new 3.1 Object methods is binding non- 
enumerable prototype properties.


> Yes. After ES3.1, I'd like to shift to your way of explaining it,  
> in terms of all values being objects. If we do this right, this  
> shift should only be a better way of explaining the same behavior.

The wrapping of primitive-this was still seen as required (optimized  
to be lazy) for compatibility, even when ES4 had string, double,  
boolean, etc value types in ES4. Breaking compatibility in ES3.1 and  
future strict modes on this point seems independent of how one models  
primitive types. Unless I'm missing something, we're only concerned  
with whether to preserve primitive |this|, breaking compatibility,  
when in strict mode; or else to wrap as in loose mode.

The spec has to wrap in loose mode. Implementations have to wrap  
(lazily, if |this| is used, etc.) in loose mode. Implementations are  
going crazy-fast these days and they avoid unnecessary wrapping, or  
will shortly. What's the reason apart from "it'll be faster" to  
change primitive |this| handling in strict mode, at a cost in spec  
and implementation complexity?

/be
/be
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.mozilla.org/pipermail/es-discuss/attachments/20080916/300d6620/attachment.html 


More information about the Es-discuss mailing list