Weird spec hole in ES3 and ES5

View: New views
8 Messages — Rating Filter:   Alert me  

Weird spec hole in ES3 and ES5

by Mark S. Miller-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

What does "Error.apply({}, [])" do? We ran into this issue in trying to fix a Caja bug. Of course, the real question for Caja must be what do browsers do today, which we can test. But I was curious what the spec said. From the way the Ch15 constructors are documented, I think in general we can't tell. ES3 and ES5 both seem to suffer from the same hole in the spec language.

The documentation of .call(), .apply(), and .bind() are in terms of invoking an internal [[Call]] (or for .bind(), also a [[Construct]]) property). However, the Ch15 constructor documentation doesn't actually mention these internal property names. It explains instead what happens when a constructor is called as a constructor (with "new"), which is probably adequate to infer the behavior of the [[Construct]] property. And it explains what happens when a constructor is called as a function. But it is not clear from the latter what, if anything, one should infer about the constructor's [[Call]]. In particular, what should happen when .call(), .apply(), or .bind() causes a Ch15 constructor's [[Call]] to be invoked with a thisArg that either 1) does not inherit from that constructor's .prototype, or 2) does not have the [[Class]] that the constructor would normally place on the newly constructed object?

This same problem arises if a Ch15 constructor is called as a method. What should "({foo: Error}).foo()" do?


One interpretation of "called as a function" in the Ch15 constructor documentation is that the thisArg (since it is never mentioned) is always ignored. This seems consistent with the behavior I just observed on FF3.0.10, Safari 3.2.3, and Chrome 3.0.189 on the Mac. This seems fine, except that it means one cannot use the normal "subclassing"ish pattern for defining new error constructors that extend Error, since Error will ignore the normal constructor chaining. Is this intended?


--
   Cheers,
   --MarkM

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Weird spec hole in ES3 and ES5

by Maciej Stachowiak :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On Jun 22, 2009, at 6:02 PM, Mark S. Miller wrote:

> What does "Error.apply({}, [])" do? We ran into this issue in trying  
> to fix a Caja bug. Of course, the real question for Caja must be  
> what do browsers do today, which we can test. But I was curious what  
> the spec said. From the way the Ch15 constructors are documented, I  
> think in general we can't tell. ES3 and ES5 both seem to suffer from  
> the same hole in the spec language.
>
> The documentation of .call(), .apply(), and .bind() are in terms of  
> invoking an internal [[Call]] (or for .bind(), also a [[Construct]])  
> property). However, the Ch15 constructor documentation doesn't  
> actually mention these internal property names. It explains instead  
> what happens when a constructor is called as a constructor (with  
> "new"), which is probably adequate to infer the behavior of the  
> [[Construct]] property. And it explains what happens when a  
> constructor is called as a function. But it is not clear from the  
> latter what, if anything, one should infer about the constructor's  
> [[Call]]. In particular, what should happen when .call(), .apply(),  
> or .bind() causes a Ch15 constructor's [[Call]] to be invoked with a  
> thisArg that either 1) does not inherit from that  
> constructor's .prototype, or 2) does not have the [[Class]] that the  
> constructor would normally place on the newly constructed object?

It could be made more clear that the "when called as a function" and  
"when called as a constructor" descriptions correspond to the [[Call]]  
and [[Construct]] internal properties respectively. Perhaps a single  
sentence at the start of the built-in object section could take care  
of this.

>
> This same problem arises if a Ch15 constructor is called as a  
> method. What should "({foo: Error}).foo()" do?
>
>
> One interpretation of "called as a function" in the Ch15 constructor  
> documentation is that the thisArg (since it is never mentioned) is  
> always ignored. This seems consistent with the behavior I just  
> observed on FF3.0.10, Safari 3.2.3, and Chrome 3.0.189 on the Mac.  
> This seems fine, except that it means one cannot use the normal  
> "subclassing"ish pattern for defining new error constructors that  
> extend Error, since Error will ignore the normal constructor  
> chaining. Is this intended?

I think this should be the behavior. Built-in or host constructors  
always make a brand-new object of a specific [[Class]], they ignore  
the object that would be passed in by "new" for a JS-implemented  
constructor function. The spec for Error seems unclear on this since  
it refers to "the newly constructed object" without clearly explaining  
how it is created.

Regards,
Maciej
 
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

RE: Weird spec hole in ES3 and ES5

by Allen Wirfs-Brock-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

>-----Original Message-----
>From: es5-discuss-bounces@... [mailto:es5-discuss-
>bounces@...] On Behalf Of Maciej Stachowiak
>Sent: Tuesday, June 23, 2009 11:19 AM
>To: Mark S. Miller
...

>> The documentation of .call(), .apply(), and .bind() are in terms of
>> invoking an internal [[Call]] (or for .bind(), also a [[Construct]])
>> property). However, the Ch15 constructor documentation doesn't
>> actually mention these internal property names. It explains instead
>> what happens when a constructor is called as a constructor (with
>> "new"), which is probably adequate to infer the behavior of the
>> [[Construct]] property. And it explains what happens when a
>> constructor is called as a function. But it is not clear from the
>> latter what, if anything, one should infer about the constructor's
>> [[Call]]. In particular, what should happen when .call(), .apply(),
>> or .bind() causes a Ch15 constructor's [[Call]] to be invoked with a
>> thisArg that either 1) does not inherit from that
>> constructor's .prototype, or 2) does not have the [[Class]] that the
>> constructor would normally place on the newly constructed object?
>
>It could be made more clear that the "when called as a function" and
>"when called as a constructor" descriptions correspond to the [[Call]]
>and [[Construct]] internal properties respectively. Perhaps a single
>sentence at the start of the built-in object section could take care
>of this.

Because built-in constructors are not (necessarily) implemented in ECMAScript code they are not required to use the definitions of [[Call]] and [[Construct]] given in 13.2.2 and 13.2.3.  Arguably the "Constructor Called as a Function" and "called as part of a new expression" sections of chapter 15 are specifying the behavior of custom [[Call]] and [[Construct]] internal methods for each built-in constructor.

I'll see if can find a way to clarify this in the introduction to chapter 15.

...

>>
>> One interpretation of "called as a function" in the Ch15 constructor
>> documentation is that the thisArg (since it is never mentioned) is
>> always ignored. This seems consistent with the behavior I just
>> observed on FF3.0.10, Safari 3.2.3, and Chrome 3.0.189 on the Mac.
>> This seems fine, except that it means one cannot use the normal
>> "subclassing"ish pattern for defining new error constructors that
>> extend Error, since Error will ignore the normal constructor
>> chaining. Is this intended?
>
>I think this should be the behavior. Built-in or host constructors
>always make a brand-new object of a specific [[Class]], they ignore
>the object that would be passed in by "new" for a JS-implemented
>constructor function. The spec for Error seems unclear on this since
>it refers to "the newly constructed object" without clearly explaining
>how it is created.
>

Actually, I think the spec. language is pretty clear on this for Error in both ES5 and ES5 (same basic language).  15.11.1 says "When Error is called as a function rather than as a constructor, it creates and initialises a new Error object. "  The phrase "the newly constructed object" in 15.11.1.1 seems to clearly be a reference to that new Error object.

Allen
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Weird spec hole in ES3 and ES5

by Mark S. Miller-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Jul 2, 2009 at 9:26 AM, Allen Wirfs-Brock <Allen.Wirfs-Brock@...> wrote:

Because built-in constructors are not (necessarily) implemented in ECMAScript code they are not required to use the definitions of [[Call]] and [[Construct]] given in 13.2.2 and 13.2.3.  Arguably the "Constructor Called as a Function" and "called as part of a new expression" sections of chapter 15 are specifying the behavior of custom [[Call]] and [[Construct]] internal methods for each built-in constructor.

The problem is that .call(), .apply(), and .bind() are specified in terms of [[Call]], so unless the connection is somehow made, it technically becomes unspecified how native constructors respond to these reflective operations.

AFAIK, the observed behavior across browsers is consistent with the theory that "called as a function" actually documents the constructor's [[Call]] method.
 

I'll see if can find a way to clarify this in the introduction to chapter 15.

Some introductory text there would be adequate. No need to propagate local changes.

In my initial message, I was also confused about whether "called as a function" was meant to cover cases such as

    foo.Error(x, y)

which I normally distinguish by saying "called as a method". If this is not unclear in the context of the rest of the ES5 spec language, no further explanatory note is needed, but may be helpful to readers as confused as I.
 

>always make a brand-new object of a specific [[Class]], they ignore
>the object that would be passed in by "new" for a JS-implemented
>constructor function. The spec for Error seems unclear on this since
>it refers to "the newly constructed object" without clearly explaining
>how it is created.
>

>I think this should be the behavior. Built-in or host constructors
Actually, I think the spec. language is pretty clear on this for Error in both ES5 and ES5 (same basic language).  15.11.1 says "When Error is called as a function rather than as a constructor, it creates and initialises a new Error object. "  The phrase "the newly constructed object" in 15.11.1.1 seems to clearly be a reference to that new Error object.

Actually, this reasoning helps clarify why there is currently a potential confusion. In a normal function call "Error(...)", there is no object explicitly passed in as the thisArg, so the spec language above does seem clear for that case. For the reflective or method cases there is an explicitly provided thisArg, so it is not unreasonable to guess that "the newly constructed object" may refer to that. Fortunately, the same simple clarification at the beginning of Ch15 should take care of this too.


--
   Cheers,
   --MarkM

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

RE: Weird spec hole in ES3 and ES5

by Allen Wirfs-Brock-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Some parts of this message have been removed. Learn more about Nabble's security policy.

Here is the language that I have inserted in the introduction to Chapter 15:

 

This section generally describes distinct behaviours for when a constructors is “called as a function” and for when it is “called as part of a new expression”. The “called as a function” behaviour corresponds to the invocation of the constructor’s [[Call]] internal method and the “called as part of a new expression” behaviour corresponds to the invocation of the constructor’s [[Construct]] internal method.

 

 

From: Mark S. Miller [mailto:erights@...]
Sent: Thursday, July 02, 2009 10:30 AM
To: Allen Wirfs-Brock
Cc: Maciej Stachowiak; Google Caja Discuss; es-discuss; es5-discuss@...
Subject: Re: Weird spec hole in ES3 and ES5

 

On Thu, Jul 2, 2009 at 9:26 AM, Allen Wirfs-Brock <Allen.Wirfs-Brock@...> wrote:

 

Because built-in constructors are not (necessarily) implemented in ECMAScript code they are not required to use the definitions of [[Call]] and [[Construct]] given in 13.2.2 and 13.2.3.  Arguably the "Constructor Called as a Function" and "called as part of a new expression" sections of chapter 15 are specifying the behavior of custom [[Call]] and [[Construct]] internal methods for each built-in constructor.


The problem is that .call(), .apply(), and .bind() are specified in terms of [[Call]], so unless the connection is somehow made, it technically becomes unspecified how native constructors respond to these reflective operations.

AFAIK, the observed behavior across browsers is consistent with the theory that "called as a function" actually documents the constructor's [[Call]] method.
 


I'll see if can find a way to clarify this in the introduction to chapter 15.


Some introductory text there would be adequate. No need to propagate local changes.

In my initial message, I was also confused about whether "called as a function" was meant to cover cases such as

    foo.Error(x, y)

which I normally distinguish by saying "called as a method". If this is not unclear in the context of the rest of the ES5 spec language, no further explanatory note is needed, but may be helpful to readers as confused as I.
 

 

>always make a brand-new object of a specific [[Class]], they ignore
>the object that would be passed in by "new" for a JS-implemented
>constructor function. The spec for Error seems unclear on this since
>it refers to "the newly constructed object" without clearly explaining
>how it is created.
>

>I think this should be the behavior. Built-in or host constructors
Actually, I think the spec. language is pretty clear on this for Error in both ES5 and ES5 (same basic language).  15.11.1 says "When Error is called as a function rather than as a constructor, it creates and initialises a new Error object. "  The phrase "the newly constructed object" in 15.11.1.1 seems to clearly be a reference to that new Error object.


Actually, this reasoning helps clarify why there is currently a potential confusion. In a normal function call "Error(...)", there is no object explicitly passed in as the thisArg, so the spec language above does seem clear for that case. For the reflective or method cases there is an explicitly provided thisArg, so it is not unreasonable to guess that "the newly constructed object" may refer to that. Fortunately, the same simple clarification at the beginning of Ch15 should take care of this too.



--
   Cheers,
   --MarkM


_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Weird spec hole in ES3 and ES5

by Mark S. Miller-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Jul 2, 2009 at 10:39 AM, Allen Wirfs-Brock <Allen.Wirfs-Brock@...> wrote:

Here is the language that I have inserted in the introduction to Chapter 15:

This section generally describes distinct behaviours for when a constructors is “called as a function” and for when it is “called as part of a new expression”. The “called as a function” behaviour corresponds to the invocation of the constructor’s [[Call]] internal method and the “called as part of a new expression” behaviour corresponds to the invocation of the constructor’s [[Construct]] internal method.

+1

--
   Cheers,
   --MarkM

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Weird spec hole in ES3 and ES5

by Maciej Stachowiak :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On Jul 2, 2009, at 10:39 AM, Allen Wirfs-Brock wrote:

Here is the language that I have inserted in the introduction to Chapter 15:
 

This section generally describes distinct behaviours for when a constructors is “called as a function” and for when it is “called as part of a new expression”. The “called as a function” behaviour corresponds to the invocation of the constructor’s [[Call]] internal method and the “called as part of a new expression” behaviour corresponds to the invocation of the constructor’s [[Construct]] internal method.


Instead of "corresponds to" I would say these behaviors "define" or "are" the [[Call]] and [[Construct]] internal properties respectively.

I also think that, given this change, the steps of actually creating new objects should be moved down to the descriptions for "called as a function" and "called as part of a new expression", instead of described separately above, to make clear that they still happen when the [[Call]] or [[Construct]] internal properties are invoked in other ways.

Regards,
Maciej



_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: Weird spec hole in ES3 and ES5

by Maciej Stachowiak :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On Jul 2, 2009, at 10:29 AM, Mark S. Miller wrote:

On Thu, Jul 2, 2009 at 9:26 AM, Allen Wirfs-Brock <Allen.Wirfs-Brock@...> wrote:

Because built-in constructors are not (necessarily) implemented in ECMAScript code they are not required to use the definitions of [[Call]] and [[Construct]] given in 13.2.2 and 13.2.3.  Arguably the "Constructor Called as a Function" and "called as part of a new expression" sections of chapter 15 are specifying the behavior of custom [[Call]] and [[Construct]] internal methods for each built-in constructor.

The problem is that .call(), .apply(), and .bind() are specified in terms of [[Call]], so unless the connection is somehow made, it technically becomes unspecified how native constructors respond to these reflective operations.

AFAIK, the observed behavior across browsers is consistent with the theory that "called as a function" actually documents the constructor's [[Call]] method.
 

I'll see if can find a way to clarify this in the introduction to chapter 15.

Some introductory text there would be adequate. No need to propagate local changes.

In my initial message, I was also confused about whether "called as a function" was meant to cover cases such as

    foo.Error(x, y)

which I normally distinguish by saying "called as a method". If this is not unclear in the context of the rest of the ES5 spec language, no further explanatory note is needed, but may be helpful to readers as confused as I.

In ECMAScript terms, what we informally call a "method call" is a kind of function call that explicitly specifies the "this" object to use for the call. So it's pretty clear to me that in the case of foo.Error(x, y), Error is being called as a function.

Regards,
Maciej


_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss