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

Mark S. Miller erights at google.com
Mon Sep 15 19:51:41 PDT 2008


On Mon, Sep 15, 2008 at 6:16 PM, Brendan Eich <brendan at mozilla.org> wrote:

> On Sep 16, 2008, at 1:54 AM, Mark S. Miller wrote:
>
> 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?
>

Worse. Since strict mode is only per program-unit, not per global object
(frame), it makes no sense for such binding to be specific to strict mode.
Rather, I'm proposing/asking whether it would be noticeably incompatible if
all browser-provided window functions were bound to their window, period.
Note that this need not be implemented or specified in terms of a specific
'bind' operation. It suffices to define all the browser-provided widow
functions to refer to their window as 'window' rather than as 'this'.

For scripted functions, it would depend on the strictness of the function. A
non-strict scripted function would still coerce the undefined 'this' to its
window, and so would see no difference.



>
> 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 think I see how we're misunderstanding each other. I am not proposing that
any bind-to-window happen by magic, nor any other radical changes to
this-binding from what we talked about. I was merely suggesting that
browser-provided window functions, in order to preserve their current
behavior when called as a function, lexically capture their window object as
'window' rather than relying on 'this' binding.

However, now that I write this, I realize we can simply explain their
current behavior by saying that they are (effectively) non-strict functions.
If this was your real point all along, sorry for the noise.



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

Please. And YUI please. Tobie has made sufficient progress getting Prototype
working under Caja that I'm fairly confident it's ok with Prototype.


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

Is this really better than a static rejection? Who gains by postponing this
failure?


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

Given that any lazy allocation has to preserve identity, as you point out,
when you can't show that 'this' doesn't escape, that preservation requires
extra bookkeeping, even if the allocation is never actually needed.


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

I'm not sure, but perhaps we're agreeing. The benefits of avoiding the
pointless wrapping of primitive 'this'es would be greatest for strict
methods added to String.prototype. Why should they pay for wrapping that
just makes their life harder anyway?



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

Yes, the two issues are independent. We were just discussing both. No need
to couple them.


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

Yes, that's the question. If we continue to explain the behavior of browser
provided window methods as non-strict functions, then there's no issue there
either. If a future browser spec wishes to explain their behavior as if they
are strict functions, then there's a possibly-minor issue, but that's
outside the scope of an ES spec.


> 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?
>
> It makes the semantics of strict mode simpler, easier to explain, less
accident-prone, and less irregular. Strict mode is our one chance to shed
some of the burdens of our previous mistakes.


-- 
   Cheers,
   --MarkM
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://mail.mozilla.org/pipermail/es-discuss/attachments/20080915/35179e4c/attachment-0001.html 


More information about the Es-discuss mailing list