eval on non-strings
Or it should call its toString method.
Sent from my smartphone.
On Sun, 26 Feb 2012 11:57:44 +0100, Xavier MONTILLET <xavierm02.net at gmail.com> wrote:
Or it should call its toString method.
That would introduce unwanted side effects. Sondier this:
eval([1, 2, 3]) right now returns [1, 2, 3]. But [1, 2, 3].toString() is '1,2,3', so you'd have eval('1,2,3') which returns 3. That makes even less sense than just returning what was given.
I really don't think anything but an exception is good there (perhaps limited to strict mode or something?)
-- Corey Richardson
On Feb 26, 2012, at 3:09 AM, Corey Richardson wrote:
On Sun, 26 Feb 2012 11:57:44 +0100, Xavier MONTILLET <xavierm02.net at gmail.com> wrote:
Or it should call its toString method.
That would introduce unwanted side effects. Sondier this:
eval([1, 2, 3]) right now returns [1, 2, 3]. But [1, 2, 3].toString() is '1,2,3', so you'd have eval('1,2,3') which returns 3. That makes even less sense than just returning what was given.
I really don't think anything but an exception is good there (perhaps limited to strict mode or something?)
Like all breaking changes, we would need to consider and gather evidence regarding whether it would have significant impact on current web content. Is the current behavior so detrimental that we should divert energy into that task?
The change can't be predicated on strict code because it concerns the definition of a built-in function that is called from any code. Strict mode restrictions must be tied to a lexical context.
On 26 February 2012 19:32, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
The change can't be predicated on strict code because it concerns the definition of a built-in function that is called from any code. Strict mode restrictions must be tied to a lexical context.
We already distinguish direct eval, which is lexical, so we could make a strict mode distinction there.
I agree it's hardly worth changing though. There are far more hazardous places where the language opts for unhelpful "soft failure", and it looks like we are even adding new ones.
Andreas Rossberg wrote:
On 26 February 2012 19:32, Allen Wirfs-Brock<allen at wirfs-brock.com> wrote:
The change can't be predicated on strict code because it concerns the definition of a built-in function that is called from any code. Strict mode restrictions must be tied to a lexical context.
We already distinguish direct eval, which is lexical, so we could make a strict mode distinction there.
I agree it's hardly worth changing though. There are far more hazardous places where the language opts for unhelpful "soft failure", and it looks like we are even adding new ones.
Fail-soft in JS1 was an artifact of lack of try-catch combined with too much rushed Unix philosophy. In cases such as delete you could get a status result (boolean telling whether the delete failed hard if false, else either succeeded or found no "own" property if true). In other cases of course an implicit coercion was done (sigh).
All water under the bridge but I agree we should not add more. Where do you see new fail-soft (or worse, fail-soft with ambiguity) being added?
On 28 February 2012 11:04, Brendan Eich <brendan at mozilla.org> wrote:
Fail-soft in JS1 was an artifact of lack of try-catch combined with too much rushed Unix philosophy. In cases such as delete you could get a status result (boolean telling whether the delete failed hard if false, else either succeeded or found no "own" property if true). In other cases of course an implicit coercion was done (sigh).
All water under the bridge but I agree we should not add more. Where do you see new fail-soft (or worse, fail-soft with ambiguity) being added?
Mainly destructuring, especially the implicit ToObject conversion of the RHS that we have discussed a couple of months ago.
Andreas Rossberg wrote:
On 28 February 2012 11:04, Brendan Eich<brendan at mozilla.org> wrote:
Fail-soft in JS1 was an artifact of lack of try-catch combined with too much rushed Unix philosophy. In cases such as delete you could get a status result (boolean telling whether the delete failed hard if false, else either succeeded or found no "own" property if true). In other cases of course an implicit coercion was done (sigh).
All water under the bridge but I agree we should not add more. Where do you see new fail-soft (or worse, fail-soft with ambiguity) being added?
Mainly destructuring, especially the implicit ToObject conversion of the RHS that we have discussed a couple of months ago.
Oh right. Another implicit conversion, indeed. We could revisit this if you feel strongly enough. It does not make me sigh though, because destructuring signals intent to pluck properties off of objects, and as I recall Allen suggested people will use this with a primitive RHS to get at prototype methods.
So I'm still in favor of the spec as proposed (and implemented in JS1.7+ in SpiderMonkey and Rhino -- no complaints or lost toes or fingers, to my knowledge).
On Feb 28, 2012, at 3:07 AM, Brendan Eich wrote:
Andreas Rossberg wrote:
On 28 February 2012 11:04, Brendan Eich<brendan at mozilla.org> wrote:
Fail-soft in JS1 was an artifact of lack of try-catch combined with too much rushed Unix philosophy. In cases such as delete you could get a status result (boolean telling whether the delete failed hard if false, else either succeeded or found no "own" property if true). In other cases of course an implicit coercion was done (sigh).
All water under the bridge but I agree we should not add more. Where do you see new fail-soft (or worse, fail-soft with ambiguity) being added?
Mainly destructuring, especially the implicit ToObject conversion of the RHS that we have discussed a couple of months ago.
Oh right. Another implicit conversion, indeed. We could revisit this if you feel strongly enough. It does not make me sigh though, because destructuring signals intent to pluck properties off of objects, and as I recall Allen suggested people will use this with a primitive RHS to get at prototype methods.
There is also a matter of maintaining internal insistency within a language. A language that consistently treats a common situation the say way everyplace it occurs is going to be easier to learn and feels more coherent than one that has contextually different behavior for the same situations. JS generally converts primitive values to wrapper objects whenever one is used in a context that requires an object. If we start throwing exceptions in new feature contexts that require an object we are making the language less internally consistent. We should want to avoid that situation.
Individual features shouldn't differ in common detail just because they were designed at different points in time or were defined by different people. These sorts of inconsistency are pretty easy to spot at the level of the code patterns used in the specification algorithms. When I see deviations of this sort in proposal that I'm incorporating into the spec. I generally just fix them.
Specifically regarding ToObject. It's use is important in minimizing the semantic differences between primitive values and Objects. In ES5 we eliminated the automatic wrapping of primitive values used as this values in method invocations. That means that in most cases 42 and (new Number(42)) can be used interchangeably. If we start leaving out ToObject calls in random places the distinction between a primitive value and a wrapped primitive values will start tripping people up.
Regarding the eval argument. It is actually the opposite situation. If it was being consistent with most of the rest of the language it would have done a ToString to its argument. But it didn't and to make it consistent now seems like a risky breaking change. It's a good example of why it is important to be consistent form the start. It's hard to correct later.
On 28 February 2012 16:54, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote:
There is also a matter of maintaining internal insistency within a language. A language that consistently treats a common situation the say way everyplace it occurs is going to be easier to learn and feels more coherent than one that has contextually different behavior for the same situations. JS generally converts primitive values to wrapper objects whenever one is used in a context that requires an object. If we start throwing exceptions in new feature contexts that require an object we are making the language less internally consistent. We should want to avoid that situation.
Individual features shouldn't differ in common detail just because they were designed at different points in time or were defined by different people. These sorts of inconsistency are pretty easy to spot at the level of the code patterns used in the specification algorithms. When I see deviations of this sort in proposal that I'm incorporating into the spec. I generally just fix them.
Specifically regarding ToObject. It's use is important in minimizing the semantic differences between primitive values and Objects. In ES5 we eliminated the automatic wrapping of primitive values used as this values in method invocations. That means that in most cases 42 and (new Number(42)) can be used interchangeably. If we start leaving out ToObject calls in random places the distinction between a primitive value and a wrapped primitive values will start tripping people up.
While I agree with this principle in general, the wider angle is that it is just an instance of the Principle of Least Surprise. And that can be a little bit more complicated. Last time round, all JS programmers on which I tested the idea of "let [x, y] = 0" not throwing were very surprised (outraged is a more accurate description in some cases).
On Tue, Feb 28, 2012 at 7:54 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote: [...]
There is also a matter of maintaining internal insistency within a language. [...] JS generally converts primitive values to wrapper objects whenever one is used in a context that requires an object. [...]
Some other violations of this rule that surprised me when I first came across them:
3 instanceof Number
false
'x' in 3
TypeError: Cannot use 'in' operator to search for 'x' in 3
I am not suggesting that we do anything to repair these -- it is likely too late. But depending on how many other such irregularities there are, it may not altogether be clear which direction the principle of least surprise should take us.
On Feb 28, 2012, at 9:20 AM, Mark S. Miller wrote:
On Tue, Feb 28, 2012 at 7:54 AM, Allen Wirfs-Brock <allen at wirfs-brock.com> wrote: [...] There is also a matter of maintaining internal insistency within a language. [...] JS generally converts primitive values to wrapper objects whenever one is used in a context that requires an object. [...]
Some other violations of this rule that surprised me when I first came across them:
3 instanceof Number
false
'x' in 3
TypeError: Cannot use 'in' operator to search for 'x' in 3
I am not suggesting that we do anything to repair these -- it is likely too late. But depending on how many other such irregularities there are, it may not altogether be clear which direction the principle of least surprise should take us.
Both of these were added to the spec. in ES3. They are probably exactly the sort of thing I was warning against when I mentioned point in time or spec. writer introduced inconsistencies. Since exceptions were also spec'ed in ES3 I bet whoever spec'ed in and instanceof thought that throwing would be the "right thing" and perhaps didn't even think about maintaining consistency with the language's legacy. who knows...
Since, in and instanceof currently throw in the above situations we probably could get away with changing them to do ToObject. Not necessarily saying we should, but it probably wouldn't break anything. It would be a set towards maintaining internal consistency.
On Tue, Feb 28, 2012 at 2:18 PM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote:
On Feb 28, 2012, at 9:20 AM, Mark S. Miller wrote:
On Tue, Feb 28, 2012 at 7:54 AM, Allen Wirfs-Brock <allen at wirfs-brock.com>wrote: [...]
There is also a matter of maintaining internal insistency within a language. [...] JS generally converts primitive values to wrapper objects whenever one is used in a context that requires an object. [...]
Some other violations of this rule that surprised me when I first came across them:
3 instanceof Number false 'x' in 3 TypeError: Cannot use 'in' operator to search for 'x' in 3
I am not suggesting that we do anything to repair these -- it is likely too late. But depending on how many other such irregularities there are, it may not altogether be clear which direction the principle of least surprise should take us.
Both of these were added to the spec. in ES3. They are probably exactly the sort of thing I was warning against when I mentioned point in time or spec. writer introduced inconsistencies. Since exceptions were also spec'ed in ES3 I bet whoever spec'ed in and instanceof thought that throwing would be the "right thing" and perhaps didn't even think about maintaining consistency with the language's legacy. who knows...
Since, in and instanceof currently throw in the above situations we probably could get away with changing them to do ToObject. Not necessarily saying we should, but it probably wouldn't break anything. It would be a set towards maintaining internal consistency.
Fixing "in" would be be great if we can. But the "instanceof" example above correctly does not throw, it returns false, which we should assume we cannot fix. "instanceof" does throw if its right operand is not an object with a [[HasInstance]] method. Is that the case you have in mind?
Allen Wirfs-Brock wrote:
Both of these were added to the spec. in ES3. They are probably exactly the sort of thing I was warning against when I mentioned point in time or spec. writer introduced inconsistencies.
Yup.
(I was off TC39 TG1 not paying close attention, founding mozilla.org
see anything relying on this, and I think that if eval is given anything but a string, an exception should be thrown.