Problems with ASP.Net object and Javascript

A

Andrew Poulos

Thus they are all conforming ECMAScript implementations.
Take arrays, a quite fundamental part of the language:

In IE:
[1,2,3,].length
is 4, it should be 3.

In FireFox:
"1" in [0,,2]
is true, should be false.

If I do this with FF 1.02:

var my = [0,,2];
if ( my[1] ) alert('true');
else alert('false');

it displays 'false'


Andrew Poulos
 
T

Thomas 'PointedEars' Lahn

Andrew said:
Thus they are all conforming ECMAScript implementations.
[...]
In FireFox:
"1" in [0,,2]
is true, should be false.

If I do this with FF 1.02:

var my = [0,,2];
if ( my[1] ) alert('true');
else alert('false');

it displays 'false'

I think this was about the `in' operation.


PointedEars

P.S.
Please provider proper attribution.
 
T

Thomas 'PointedEars' Lahn

Lasse said:
But claiming to be compliant and not being it, suggests that the
noncompliance is due to a bug, not a deliberate choice.

It should be noticed that JScript is not claimed to be compliant:
<URL:http://msdn.microsoft.com/library/en-us/script56/html/js56jscon
about.asp>

Rhino and SpiderMonkey do claim compliance:
<URL:http://www.mozilla.org/js/>

IBTD:

"with only minor exceptions ..., ... a full implementation" (M$) and
"a superset ... with mild differences" (Mozilla.org) is much the same
to me.


PointedEars
 
L

Lasse Reichstein Nielsen

Andrew Poulos said:
Take arrays, a quite fundamental part of the language: .....
In FireFox:
"1" in [0,,2]
is true, should be false.
If I do this with FF 1.02:

var my = [0,,2];
if ( my[1] ) alert('true');
else alert('false');

it displays 'false'

As it should.

The "in" operator takes a string and an object, and gives true
if the object has a property with the name in string. E.g.

var o = {foo:42};
alert(["foo" in o, "bar" in o]);

It alerts "true,false".

An object might have a property with a value that is "falsey" (converts
to false as a boolean), even "undefined".

var o = {foo: undefined};
alert(["foo" in o, "bar" in o]);
alert([o["foo"],o["bar"]]);

alerts first "true,false", then "undefined,undefined".

There is a difference between not having the property, and having the
property with the value "undefined", even if attempting to read either
gives the same result (undefined).


The array literal [0,,2] should not have a property called "1"
according to the ECMAScript standard. The error in FireFox/Gecko's
ECMAScript implementation is that that it does, it just has the value
"undefined". It's a very minor and insignificant error, which is
probably why it hasen't been fixed, but it *is* an error.

/L
 
L

Lasse Reichstein Nielsen

Thomas 'PointedEars' Lahn said:
IBTD:

"with only minor exceptions ..., ... a full implementation" (M$) and
"a superset ... with mild differences" (Mozilla.org) is much the same
to me.

Yes, but the Mozilla page also says "Like SpiderMonkey, Rhino is
ECMA-262 Edition 3 compliant.". However vague they are in other
places, that line is either too clear to misinterpret. It might be
wrong, but it's not ambiguous :)

/L
 
T

Thomas 'PointedEars' Lahn

Lasse said:
The array literal [0,,2] should not have a property called "1"
according to the ECMAScript standard. [...]

Yes, it should. As of ECMAScript 3, Subsection 11.1.4 (Array Initialiser),
`[0,,2]' is the literal notation of an Array object with the following
structure and content (written as an object literal):

{"0": 0,
"1": undefined, // which is why its value converted to `false'
"2": 2,
// following other Array object specific properties like `length';
// from now on: `...'
}

The productions are:

ArrayLiteral :
[ Elision_opt ]
[ ElementList ]
[ ElementList , Elision_opt ]

ElementList :
Elision_opt AssignmentExpression
ElementList , Elision_opt AssignmentExpression

Elision :
,
Elision ,

"[0,,2]" can be produced by

ArrayLiteral
=> [ ElementList ]
=> [ ElementList , Elision_opt AssignmentExpression ]
=> [ Elision_opt AssignmentExpression , Elision_opt AssignmentExpression ]
=> [ AssignmentExpression , Elision_opt AssignmentExpression ]
=> ...
=> [ 0 , Elision_opt 2 ]
=> [ 0 , , 2 ]

and is therefore evaluated as follows:

...
[ ElementList , Elision_opt AssignmentExpression ]
| 1. Evaluate ElementList.
Evaluate production `ElementList : Elision_opt AssignmentExpression'
| 1. Create a new array as if by the expression new Array().
=> {...} == []
| 2. Evaluate Elision; if not present, use the numeric value zero.
=> 0
| 3. Evaluate AssignmentExpression.
=> 0
| 4. Call GetValue(Result(3)).
=> 0
| 5. Call the [[Put]] method of Result(1) with arguments Result(2)
| and Result(4).
=> [].[[Put]](0, 0)
=> {"0": 0, ...} == [0]
| 6. Return Result(1)
=> [0]

| 2. Evaluate Elision; if not present, use the numeric value zero.
Evaluate production `Elision : ,'
| 1. Return the numeric value 1.
=> 1

| 3. Evaluate AssignmentExpression.
=> 2

| 4. Call GetValue(Result(3)).
=> 2

| 5. Call the [[Get]] method of Result(1) with argument "length".
=> [0].[[Get]]("length")
=> 1

| 6. Call the [[Put]] method of Result(1) with arguments
| (Result(2)+Result(5)) and Result(4).
=> [0].[[Put]](1+1, 2)
=> [0].[[Put]](2, 2)

| 8.6.2.2 [[Put]] (P, V)
|
| 1. Call the [[CanPut]] method of O with name P.
=> true
| 2. If Result(1) is false, return.
| 3. If O doesn?t have a property with name P, go to step 6.
| [...]
| 6. Create a property with name P, set its value to V and give
| it empty attributes.
| 7. Return.

Now you assume that step 6.6. results in an object with the following
structure and content:

{"0": 0,
"2": 2,
...
}

However, ECMAScript 3 also states:

| 11.1.4 Array Initialiser
| [...]
| Array elements may be elided at the beginning, middle or end of the
| element list. Whenever a comma in the element list is not preceded
| by an AssignmentExpression (i.e., a comma at the beginning or after
| another comma), the missing array element contributes to the length
| of the Array and increases the index of subsequent elements.
| Elided array elements are not defined.

Since in "[0, , 2]", the second "comma in the element list is not preceded
by an AssignmentExpression", to be exact, is "a comma [...] after another
comma", "the missing array element ..." [continue reading above]. And so:

| 7. Return Result(1)
=> [0, undefined, 2]

The `in' operation returns `true' if/while the second operand has a
property named as the first operand; since that property ("1") exists
here, it returns `true'. (The property's value does not matter, as
you just explained.)
The error in FireFox/Gecko's ECMAScript implementation is that that
it does, it just has the value "undefined".

It is not an error :)


PointedEars
 
R

Richard Cornford

Thomas said:
Lasse said:
The array literal [0,,2] should not have a property called "1"
according to the ECMAScript standard. [...]

Yes, it should.

No it should not. Even in your description of the process you will not
find a call to the Array [[Put]] method with "1" as its property name.

[ ElementList , Elision_opt AssignmentExpression ]
| 1. Evaluate ElementList.
Evaluate production `ElementList : Elision_opt
AssignmentExpression' | 1. Create a new array as if by the
expression new Array(). => {...} == []

This newly created Array object, disregarding its internal properties
and the properties it inherits through its prototype, has one property
with the name 'length' and the value zero.

| 5. Call the [[Put]] method of Result(1) with arguments
Result(2) | and Result(4).
=> [].[[Put]](0, 0)

This is the first [[Put]] call on the Array object, creating a property
with the name "0" and the value 0.

| 6. Call the [[Put]] method of Result(1) with arguments
| (Result(2)+Result(5)) and Result(4).
=> [0].[[Put]](1+1, 2)
=> [0].[[Put]](2, 2)

This is the second call to the Array's [[Put]] method, it creates a
property with the name "2" and the value 2.
| 8.6.2.2 [[Put]] (P, V)

This is not the special Array [[Put]] method's algorithm. For that see
section 15.4.5.1. The main difference between the Object [[Put]] method
and the array [[Put]] method is the handling of property names that
correspond with 32 bit unsigned integers with regard to interactions
with the Array's - length - property.

| 7. Return.

Now you assume that step 6.6. results in an object with the following
structure and content:

{"0": 0,
"2": 2,
...
}

It would be more accurate to characterise this object as;-

{
'0':0,
'2':2,
'length':3
}

(baring in mind that this object would have the Array prototype rather
than the Object prototype)

That is; two calls to the [[Put]] method have created two named
properties on the Array object, and the pre-existing - length - property
has been adjusted to have the value 3.
However, ECMAScript 3 also states:

| 11.1.4 Array Initialiser
| [...]
| Array elements may be elided at the beginning, middle or end
| of the element list. Whenever a comma in the element list
| is not preceded by an AssignmentExpression (i.e., a comma
| at the beginning or after another comma), the missing array
| element contributes to the length of the Array and increases
| the index of subsequent elements. Elided array elements are
| not defined.

This describes how the Array's _length_ property may be altered but does
not imply that any _named_properties_ will be created on the Array
object beyond those specified in the algorithms you cited above.
Since in "[0, , 2]", the second "comma in the element list
is not preceded by an AssignmentExpression", to be exact,
is "a comma [...] after another comma", "the missing array
element ..." [continue reading above]. And so:

| 7. Return Result(1)
=> [0, undefined, 2]

This is a less clear description of the resulting array than the Object
literal notation above. No assignment has been made with the name "1" so
the Array object does not have a property of that name, and not having a
property of that name that non-existent property does not have the value
Undefined. While the resulting Array will effectively/practically be the
same as the Array literal listed above that is only because reading a
property of an object using a name that does not correspond with a named
property of that object will return undefined.
The `in' operation returns `true' if/while the second operand
has a property named as the first operand;

True, where 'has a property' is determined by the Array object's
internal [[HasProperty]] method.

<quote cite="ECMA262 3rd edition, Section 8.6.2.4">
8.6.2.4 [[HasProperty]] (P)

When the [[HasProperty]] method of O is called with property
name P, the following steps are taken:

1. If O has a property with name P, return true.
2. If the [[Prototype]] of O is null, return false.
3. Call the [[HasProperty]] method of [[Prototype]] with
property name P.
4. Return Result(3).
</quote>

But as at no point in the creation of the Array object from the Array
literal was a property with the name "1" created (and its prototype does
not have one either), [[HasProperty]]('1') returns false.
since that property ("1") exists
here, it returns `true'.

If at no point in the algorithm applied to the creation of the Array
from the Array literal there was a call to [[Put]]('1', x) then the
property does _not_ exist.

It is not an error :)

Following the ECMA algorithms for the creation of Array objects from
Array literals, and the - in - operator, the behaviour of FireFox, as
described, does not produce the correct outcome. That sounds like an
error to me.

(For future reference, when Lasse asserts that the ECMA production rules
and algorithms should produce results that do not correspond with your
expectations it is best to double and triple check against ECMA 262,
because I have not known Lasse to be wrong on the subject to date.)

Richard.
 
L

Lasse Reichstein Nielsen

Thomas 'PointedEars' Lahn said:
Lasse said:
The array literal [0,,2] should not have a property called "1"
according to the ECMAScript standard. [...]

Yes, it should. As of ECMAScript 3, Subsection 11.1.4 (Array Initialiser),
`[0,,2]' is the literal notation of an Array object with the following
structure and content (written as an object literal):

[snip derivation]
Now you assume that step 6.6. results in an object with the following
structure and content:

{"0": 0,
"2": 2,
...
}

I do. It does. Your derivation is absolutely correct. The structure
is exactly {"0":0, "2":2, "length":3} plus the attributes inherited
from Array.prototype.

Looking at the derivation, one can notice that a call to [[Put]]
is only made once for each AssignmentExpression in the derivation.
That's one for each of "0" and "2", so there won't be any property
named "1".
However, ECMAScript 3 also states:

| 11.1.4 Array Initialiser

Snip explanation of how elided elements work: they increase the
indices of the following elements without.
| Elided array elements are not defined.

Since in "[0, , 2]", the second "comma in the element list is not preceded
by an AssignmentExpression", to be exact, is "a comma [...] after another
comma", "the missing array element ..." [continue reading above]. And so:

| 7. Return Result(1)
=> [0, undefined, 2]

No, return the array created in line 1. of the rule for
"ElementList : Elision_opt AssignmentExpression", which has since
been modified by calls to [[Put]](0,0) and [[Put]](2,2). It has
no property called "1".

The array literal [0, undefined, 2] has a different derivation,
one that, while evaluated, makes three calls to [[Put]] on the array,
the second with the two arguments, 1 and undefined.
The `in' operation returns `true' if/while the second operand has a
property named as the first operand; since that property ("1") exists
here, it returns `true'. (The property's value does not matter, as
you just explained.)

Except that it doesn't exist, because no call to [[Put]] have been
made with a first argument of 1.

[Firefox evaluates "1 in [0,,2]" to true]
It is not an error :)

Sure it is :)

Both IE and Opera gives the correct result.
/L
 
T

Thomas 'PointedEars' Lahn

Lasse said:
Thomas 'PointedEars' Lahn said:
Lasse said:
The array literal [0,,2] should not have a property called "1"
according to the ECMAScript standard. [...]
Yes, it should. As of ECMAScript 3, Subsection 11.1.4 (Array
Initialiser), `[0,,2]' is the literal notation of an Array object with
the following structure and content (written as an object literal):

[snip derivation]
Now you assume that step 6.6. results in an object with the following
structure and content:

{"0": 0,
"2": 2,
...
}

I do. It does. Your derivation is absolutely correct. The structure
is exactly {"0":0, "2":2, "length":3} plus the attributes inherited
from Array.prototype.

Looking at the derivation, one can notice that a call to [[Put]]
is only made once for each AssignmentExpression in the derivation.
That's one for each of "0" and "2", so there won't be any property
named "1".

I included the derivation only for matters of completeness. My point is
that its result does not really matter for a real implementation since
there is special behavior defined, see below.
Snip explanation of how elided elements work: they increase the
indices of the following elements without.

I don't think so.

Together with what you snipped, that means they may exist and have the
value of `undefined', yes?
Since in "[0, , 2]", the second "comma in the element list is not
preceded by an AssignmentExpression", to be exact, is "a comma [...]
after another comma", "the missing array element ..." [continue reading
above]. And
so:

| 7. Return Result(1)
=> [0, undefined, 2]

No, return the array created in line 1. of the rule for
"ElementList : Elision_opt AssignmentExpression", which has since
been modified by calls to [[Put]](0,0) and [[Put]](2,2). It has
no property called "1".

You suggest it to have a length (number of elements) of 3
but do not have a second element. That's ridiculous.
The array literal [0, undefined, 2] has a different derivation,
one that, while evaluated, makes three calls to [[Put]] on the array,
the second with the two arguments, 1 and undefined.

Following described *evaluation process* in ECMAScript, yes.
The `in' operation returns `true' if/while the second operand has a
property named as the first operand; since that property ("1") exists
here, it returns `true'. (The property's value does not matter, as
you just explained.)

Except that it doesn't exist, because no call to [[Put]] have been
made with a first argument of 1.

Does not matter. As a specialty of Array objects which are defined to
be dynamic, there should be (and is in JavaScript) a property named "1"
created (unless you want to complicate usage).
[Firefox evaluates "1 in [0,,2]" to true]
It is not an error :)

Sure it is :)

Both IE and Opera gives the correct result.

I don't think it is an error and I don't think there is such as a correct
result here. Both IE and Opera do not implement Netscape JavaScript; IE
implements M$ JScript, Opera implements something else. ECMAScript does
not explicitely forbid the "1" property to be created implicitely. And
as Richard recently pointed out,

| [...] a conforming implementation of ECMAScript is permitted to
| provide properties not described in this specification [...]
|
| A conforming implementation of ECMAScript is permitted to support
| program [...] syntax not described in this specification.

AIUI, that includes creating properties/elements with value `undefined'
implicitely for Array objects if they are elided in an Array initialiser.


PointedEars
 
L

Lasse Reichstein Nielsen

[Array [0,,2]]
You suggest it to have a length (number of elements) of 3
but do not have a second element. That's ridiculous.

You are free to think that, but it is how it is defined.

Doing:
var a = [0];
a[1000] = 42;
alert(1 in a);

will yield false, even in FireFox, so it's not completely ridiculous
to have a sparse array with length==1001 and only two defined
properties.

The definition of [[Put]] on arrays (section 15.4.5.1) specifies how
the length property is set. It is an invariant that the length
property of an array is at least one larger than the largest "array
index" (normalized integer < 2^32) property (section 15.4), but it can
be larger.
I don't think it is an error and I don't think there is such as a correct
result here. Both IE and Opera do not implement Netscape JavaScript; IE
implements M$ JScript, Opera implements something else. ECMAScript does
not explicitely forbid the "1" property to be created implicitely. And
as Richard recently pointed out, ....
AIUI, that includes creating properties/elements with value `undefined'
implicitely for Array objects if they are elided in an Array initialiser.

Ok, so your argument is that having a standard operation do more than
what the standard requires is not necessarily an error. I am not sure
I can agree to that.

Section 2 (Conformance) states that a conforming implementation must
supporty the semantics described in the specification. The semantics
of the literal [0,,2] is clearly specified. Giving the same expression
a different semantics would not be compliant. An "extension of the
semantics" is, to me, a different semantics.

There is a difference between extending the language, be it with extra
functions, objects, properties or even extra functionality for
existing functions (as they warn against), and changing the semantics
for the existing language. The evaluation of the array literal is
fully within the core language, and should have the specified
semantics.


Anyway, it's in bugzilla
<URL:https://bugzilla.mozilla.org/show_bug.cgi?id=260106>


For another, perhaps more clearly defined, bug in Mozilla's ECMAScript:
---
var x = [0];
x[2] = 2; // now: 1 in x == false
x.sort();
alert(2 in x); // should be false, is true.
---
Sort should only rearrange existing properties, it should not create
new. What happens here is that the result becomes [0,2,undefined],
and not [0,2,] as it should (Section 15.4.4.11, especially first dot
describing the returned object's properties).

/L
 
R

Richard Cornford

Thomas said:
Lasse said:
Thomas 'PointedEars' Lahn wrote:
Since in "[0, , 2]", the second "comma in the element
list is not preceded by an AssignmentExpression", to be
exact, is "a comma [...] after another comma", "the
missing array element ..." [continue reading above]. And
so:

| 7. Return Result(1)
=> [0, undefined, 2]

No, return the array created in line 1. of the rule for
"ElementList : Elision_opt AssignmentExpression", which
has since been modified by calls to [[Put]](0,0) and
[[Put]](2,2). It has no property called "1".

You suggest it to have a length (number of elements) of 3
but do not have a second element. That's ridiculous.

Maybe that is a consequence of reading the algorithm for the Object's
[[Put]] method where the algorithm for the Array [[Put]] method really
applies to the process:-

<quote cite="ECMA 262 3rd edition Section 15.4.5.1">
15.4.5.1 [[Put]] (P, V)

Array objects use a variation of the [[Put]] method used
for other native ECMAScript objects (section 8.6.2.2).

Assume A is an Array object and P is a string.

When the [[Put]] method of A is called with property P
and value V, the following steps are taken:

1. Call the [[CanPut]] method of A with name P.
2. If Result(1) is false, return.
3. If A doesn't have a property with name P, go to step 7.
4. If P is "length", go to step 12.
5. Set the value of property P of A to V.
6. Go to step 8.
7. Create a property with name P, set its value to V and
give it empty attributes.
8. If P is not an array index, return.
9. If ToUint32(P) is less than the value of the length
property of A, then return.
10. Change (or set) the value of the length property of A
to ToUint32(P)+1.
11. Return.
12. Compute ToUint32(V).
13. If Result(12) is not equal to ToNumber(V), throw a
RangeError exception.
14. For every integer k that is less than the value of the
length property of A but not less than Result(12), if A
itself has a property (not an inherited property) named
ToString(k), then delete that property.
15. Set the value of property P of A to Result(12).
16. Return.
</quote>

Which needs to be suplimented with the defenition of "array index"
provided at the beginning of section 15.4:-

<quote cite="ECMA 262 3rd edition section 15.4">
A property name P (in the form of a string value) is an array
index if and only if ToString(ToUint32(P)) is equal to P and
ToUint32(P) is not equal to [1] 2<sup>32</sup> -1.
</quote>
[1: two to the power of 32, minus one]

So given the code:-

var a = new Array();
a[100] = 1;

- the resulting array object resembles:-

{
'100':1,
'length':101
}

- because the property name qualifies as an "array index" and the
[[Put]] algorithm assigns a value to the Array's - length - property
that is one greater than the numeric equivalent of the property name.

The `in' operation returns `true' if/while the second
operand has a property named as the first operand; since
that property ("1") exists here, it returns `true'.
(The property's value does not matter, as you just explained.)

Except that it doesn't exist, because no call to [[Put]] have
been made with a first argument of 1.

Does not matter. As a specialty of Array objects which are
defined to be dynamic, there should be (and is in JavaScript)
a property named "1" created (unless you want to complicate
usage).

All objects ECMAScript, including arrays, are augmented instances of the
native ECMAScript object, which supports the dynamic adding of named
properties at runtime.

The augmentations that apply to the Array objects are that an
alternative [[Put]] method is used, and the constructor adds a -
length - property and initialises it to zero. And that, combined with
the normal behaviour of the Object's [[Get]] method (returning -
undefined - when an object does not have a property with the requested
name), is all that is necessary to turn a dynamic object into a dynamic
sparse Array implementation.

These three details provide the array-ness of an Array, end explain why
array-ness has nothing to do with the use of an Object as a "hashtable"
or "associative array".

ECMAScript simply does not need to create a property with the name "1"
and the value - undefined - for the Array literal - [ 0, , 2 ] -
because reading a property with that name will return - undefined -
whenever the property does not exist.

And there is a great deal to be said for a dynamic spars array
implementation not creating actual named properties for all 'elements'
in an Array. Consider:-

var a = new Array();
a[4294967295] = 0;

If all the named properties were created on the Array object the result
would resemble:-

{
'0':undefined,
'1':undefined,
...
'4294967294':undefined,
'4294967295':0,
'length':4294967296
}

- and probably exceed the entire memory map in 32 bit operating system.
While;-

{
'4294967295':0,
'length':4294967296
}

- is a trivial object.

In terms of the normal use of an Array there would be no difference
(assuming the resources where available to accommodate the first, and
disregarding the performance differences in property resolution).

It is clearly not a good idea to add named properties to an Array to
fill in gaps when an element is created with a large 'array index' . So
the Array should be able to accommodate having many fewer actual
properties than its - length - property might imply. And under those
circumstances there is no reason to expect special behaviour form the
creation of an Array using an Array literal.

... . ECMAScript does not explicitely forbid the "1"
property to be created implicitely. And as Richard
recently pointed out,

| [...] a conforming implementation of ECMAScript is
| permitted to provide properties not described in this
| specification [...]
|
| A conforming implementation of ECMAScript is permitted
| to support program [...] syntax not described in this
| specification.

AIUI, that includes creating properties/elements with
value `undefined' implicitely for Array objects if they
are elided in an Array initialiser.

The conformance section has two 'Must' paragraphs followed by two 'May'
(expressed as "is permitted to") paragraphs. While the algorithms that
define the semantics certainly do not result in the creation of a
property named "1" it might be argued that freedom to provide additional
properties provided by the 'May' paragraphs could accommodated its
creation during the process.

It might also be argued that where an algorithm for a process describes
the changes made to an object during that process the changes made to
that object should not exceed those stated in the algorithm (at least to
the extent that those changes are publicly determinable).

It makes perfect sense to me that the language should allow for
additional named properties of an array that apply to all Array objects
from their creation. But adding a property to an object during a
specified process seems to require additional steps in the applicable
algorithms, and additional steps in an algorithm means that it is a
different algorithm, and so does not conform to ECMA 262.

Richard.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top