Re: This binding and ES5 builtins

On Jul 7, 2011, at 10:33 AM, Luke Hoban wrote:

> Interesting – this is not what I expected.  That interpretation implies that ES5 intentionally diverged from the behaviour that has been standard in all major browsers (until some starting changing recently) as far as I can tell.  Has there been previous discussion of the compatibility implications?

Yes, this was discussed, a while ago:

https://mail.mozilla.org/pipermail/es-discuss/2008-September/007417.html

is the thread head, click on the [ thread ] link to see the followups. Some of this thread was about wrapping primitives but some was about global function calls and |this|.


>  Note that for the original two test cases, here is the results I see – which seems to offer historical (and current) support for the alternative interpretation:
>  
> >> (1, Object.prototype.hasOwnProperty)('abc')
> IE6: false, IE9: false, IE10: false, FF3: false, FF4: TypeError, Chrome13: false, Chrome14: false, Safari5: false, Opera11: false

Only FF4 follows ES5 (including the missing link wanted in Clause 15)? D'oh.

It's still edge-case enough that I think other browsers can follow. People do not much call built-ins with funny callee expressions such as (1, {}.hasOwnProperty) -- and doing so leaks the global object capability, which is the problem ES5 intended to fix.


>  >>  var f = Object.prototype.hasOwnProperty
> >>  f('abc')
> IE6: false, IE9: false, IE10: false, FF3: false, FF4: TypeError, Chrome13: false, Chrome14: TypeError, Safari5: false, Opera11: false
>  
> Saying that undefined should be passed to built-ins feels like it is strict mode bleeding out of the strict mode opt-in.

No strict mode here. As Mark wrote, built-ins are neither strict nor non-strict.


> In non-strict, in practice, the “global object” (leaving aside multiple globals for now) is passed as this to unbound function calls, irrespective of whether they are native, built-in or host functions.  Why is this being changed to undefined outside of strict mode?

See the recent messages on this thread. ES3 did not specify that "the global object" was passed by caller-side code (the semantics for CallExpression). Rather, those semantics passed null. ES3 then failed to say what built-ins (or common glue used to call them) did to recover the global object.


>  I would expect that if 13.2.1 is not relevant to built-ins, then the built-ins should have some other spec section that accomplishes the relevant parts of 13.2.1, in particular, the this-binding fix-up. 

Yes, Clause 15 needs a bit more work -- Allen said he'd fix.


>  Also, the note that “if a host supplied function is somehow converting this/undefined to the caller's global object it is doing something magical”, is concerning.  As far as I understand, with multiple globals, the web-compatible behaviour is to pass the caller-side global.

No! Ah, I see Oliver replied.

The situation with caller-side |this| computation in non-strict global code is not to pass null or undefined and then replace that with the dynamic scope's global object. Rather, property lookup computes a Reference for the unqualified global property name used as the callee expression, and that Reference base is the exactly the global object in which the global property was found.

This is lexical not dynamic scope, in the caller evaluation context. It predates ES5 and it cannot be modeled with callee-based |this| rectification. It's why we did not "fix" https://bugzilla.mozilla.org/show_bug.cgi?id=634590 is Firefox 4.


>   Pushing the burden of managing this to something magical the host functions need to take care of feels like the wrong direction, given what standard practice appears to have been.

There's no need for magic if we can get this spec'ed fully.

/be

Received on Thursday, 7 July 2011 18:06:24 UTC