Object Hash vs. object Array preference

V

VK

Hello,
In my object I have getDirectory() method which returns 2-dimentional
array
(or an imitation of 2-dimentional array using two JavaScript objects
with auto-handled length property - please let's us do not go into an
"each dot over i" clarification discussion now - however you want to
call - you call it ;-)

array[0] contains records of all files in the current dir.
array[1] contains records of all subs in the current dir

Each records is in its turn is an array of 6 elements: file/folder
name, size, type, attributes, lastModified date, lastModified time.

Tking into account that someone will need to build a dialog interface
over this data IMHO array structure is the most suitable ('cause of
sorting issue).

Or a custom object on each directory entry still would be more
flexible? What would you personally prefer to get out of the functiuon
for easier programming?
 
T

Thomas 'PointedEars' Lahn

VK said:
In my object I have getDirectory() method which returns 2-dimentional
array
(or an imitation of 2-dimentional array using two JavaScript objects
with auto-handled length property - please let's us do not go into an
"each dot over i" clarification discussion now - however you want to
call - you call it ;-)

I can accept the term "2-dimensional array" for brevity, provided that
each element has the same number of subelements.
array[0] contains records of all files in the current dir.
array[1] contains records of all subs in the current dir

Each records is in its turn is an array of 6 elements: file/folder
name, size, type, attributes, lastModified date, lastModified time.

Tking into account that someone will need to build a dialog interface
over this data IMHO array structure is the most suitable ('cause of
sorting issue).

I don't understand this argument. What has sorting to do with it?
Or a custom object on each directory entry still would be more
flexible? What would you personally prefer to get out of the functiuon
for easier programming?

I'd prefer an Object-based object here since it is more difficult to
remember the index of the array element than the meaningful identifier
of the property. If needed later, an Array object can be extended to
a collection so that both access methods can be used.


PointedEars
 
V

VK

VK said:
..
Thomas 'PointedEars' Lahn wrote:
I don't understand this argument. What has sorting to do with it?

I meant to say that you cannot sort hash keys (object properties,
collection items - the Legion is its name) but you can sort arrays.
Need to admit though that in case like
record[e1, e2, e3, e4, e5] > sort all records by e4
I'm pretty cloudy about the best accepted mechanics and therefore I'm
not sure what to serve better: an Object or an Array. I used to handle
such issues on server-side through mySQL where the boring part is done
automatically on the background.
..
Thomas 'PointedEars' Lahn wrote:
I'd prefer an Object-based object here since it is more difficult to
remember the index of the array element than the meaningful identifier
of the property. If needed later, an Array object can be extended to
a collection so that both access methods can be used.
That's not so much a question of usability but a question of
productivity.
Firstly the served object will be used for LOOKUP operations
exclusively (you cannot delete files/properties or add new ones here).
Secondly it will be used for LOOKUP operations very intensively. On a
big directory (over 100 files) display/sorting/selection will take
thousands of lookups so even 1ms difference will add up easily. I guess
it brings up the old question: is there any productivity difference
between Object and Array for lookup operations?
 
L

Lasse Reichstein Nielsen

VK said:
I meant to say that you cannot sort hash keys (object properties,
collection items - the Legion is its name) but you can sort arrays.

Sorting implies ordering, which again implies indexability by counting
numbers, so yes, array elements can be sorted, rearranging their
property names. There is no ordering of general properties of objects,
so it's not even possible to define a notion of sorting on them.
Need to admit though that in case like
record[e1, e2, e3, e4, e5] > sort all records by e4

Not understood. If each record is a five element array, and you want
to sort it by its fourth element, then I'd do something like:
---
// generic comparison function
function cmp(a,b) {
return (b<a)-(a<b);
}

// creates function that compares property prop of arguments.
function cmpProperty(prop) {
return function (a,b) {
return cmp(a[prop],b[prop]);
};
}

// sort records by fourth element.
records.sort(cmpProperty(3));
---
I'm pretty cloudy about the best accepted mechanics and therefore I'm
not sure what to serve better: an Object or an Array.

Doesn't matter. You compare a property of the object, whether it's
called "3" or "foo" is irrelevant. So if you use the record anywhere
else, use meaningful names.

I guess it brings up the old question: is there any productivity
difference between Object and Array for lookup operations?

That depends on the implementation of Javascript it is running on.

A quick test:
---
function timeLookup(obj,prop, N) {
var t0 = new Date();
var x;
while(N--) {
x = obj[prop];
}
var t1 = new Date();
return t1-t0;
}

var N = 1000000;
var a = ["lal","lal","lala","lalala","lalalaalla"];
var t0 = timeLookup(a,"3", N);
var t1 = timeLookup(a,3, N);

var o = {"diller":"lal","daller":"lal","y":"lala","3":"lalala",
"anguish":"lalalaalla"};
var t2 = timeLookup(o, "3", N);

var o2 = {"diller":"lal","daller":"lal","y":"lala","x":"lalala",
"anguish":"lalalaalla"};
var t3 = timeLookup(o2, "x", N);

var o3 = {"diller":"lal","daller":"lal","y":"lala",
"dallerdallerdaller":"lalala","anguish":"lalalaalla"};
var t4 = timeLookup(o3, "dallerdallerdaller", N);

[t0,t1,t2,t3,t4]
---
gives the following results (times in ms):
array["3"] array[3] object["3"] object["x"] object["daller...."]
Opera 922 766 906 797 843
IE 6 906 891 891 937 1093
FF 746 406 750 625 906

So, of these, only Firefox seems to have a significantly more
efficient array lookup than property lookup, but longer property
names makes for longer lookup times.

It should probably also be tested on objects/arrays with lots
of properties, not just five.

Both Opera and Firefox seems to take extra time when the property is a
string containing a number literal, even when used on an object, not
an array. One can wonder why :)

/L
 
V

VK

Lasse Reichstein Nielsen wrote:
If each record is a five element array, and you want
to sort it by its fourth element, then I'd do something like:
---
// generic comparison function
function cmp(a,b) {
return (b<a)-(a<b);
}

// creates function that compares property prop of arguments.
function cmpProperty(prop) {
return function (a,b) {
return cmp(a[prop],b[prop]);
};
}

// sort records by fourth element.
records.sort(cmpProperty(3));

A quick test:
---
function timeLookup(obj,prop, N) {
var t0 = new Date();
var x;
while(N--) {
x = obj[prop];
}
var t1 = new Date();
return t1-t0;
}

var N = 1000000;
var a = ["lal","lal","lala","lalala","lalalaalla"];
var t0 = timeLookup(a,"3", N);
var t1 = timeLookup(a,3, N);

var o = {"diller":"lal","daller":"lal","y":"lala","3":"lalala",
"anguish":"lalalaalla"};
var t2 = timeLookup(o, "3", N);

var o2 = {"diller":"lal","daller":"lal","y":"lala","x":"lalala",
"anguish":"lalalaalla"};
var t3 = timeLookup(o2, "x", N);

var o3 = {"diller":"lal","daller":"lal","y":"lala",
"dallerdallerdaller":"lalala","anguish":"lalalaalla"};
var t4 = timeLookup(o3, "dallerdallerdaller", N);

[t0,t1,t2,t3,t4]
---
gives the following results (times in ms):
array["3"] array[3] object["3"] object["x"] object["daller...."]
Opera 922 766 906 797 843
IE 6 906 891 891 937 1093
FF 746 406 750 625 906

So, of these, only Firefox seems to have a significantly more
efficient array lookup than property lookup, but longer property
names makes for longer lookup times.

Wow: double speed gain on Array with FF. These are 1-10 seconds speed
gain for application I guess - if you manage to stay within Array only.
IE seems rather indifferent but still just a bit quicklier. So I'd
explore Array-only solutions first if any is possible.
It should probably also be tested on objects/arrays with lots
of properties, not just five.

That's not my case, but I'd welcome any volunteer ;-)
Both Opera and Firefox seems to take extra time when the property is a
string containing a number literal, even when used on an object, not
an array. One can wonder why :)

Was that a rhetorical question? :)
Naturally arr["3"] takes longer because the system is trying to find
first CDATA-named property "1", fails on that and only then it gets
array element with index 3.
 
T

Thomas 'PointedEars' Lahn

VK said:
Lasse said:
Both Opera and Firefox seems to take extra time when the property is a
string containing a number literal, even when used on an object, not
an array. One can wonder why :)

Was that a rhetorical question? :)
Naturally arr["3"] takes longer because the system is trying to find
first CDATA-named property "1", fails on that and only then it gets
array element with index 3.

CDATA is a data type specified in SGML/XML and used in DTDs for markup
languages. We are talking about a programming language specification
and its implementation, particularly ECMAScript 3 [1], subsection 11.2.1.

Will you learn how to quote?


PointedEars
___________
[1] <http://www.mozilla.org/js/language/E262-3.pdf>
 
V

VK

Thomas 'PointedEars' Lahn wrote:
CDATA is a data type specified in SGML/XML and used in DTDs for markup
languages. We are talking about a programming language specification
and its implementation, particularly ECMAScript 3 [1], subsection 11.2.1.

?

JavaScript/JScript Object accepts CDATA literals as property name.

Array index is unsigned 32 bit value which allows you to hold
4294967295 array elements per array-that's one less than 32 bits can
hold: the remaining one is used for the length value.

So in case:
someObject["3"] = "foo";
interpreter checks first if the key can be converted into an integer in
the range 0,..., 4294967295
If it can then someObject is treated as array (if contextually
possible) and its element with index 3 gets value "foo".

If the key cannot be converted into integer or if such integer goes
outside of the 0,..., 4294967295 range then the value is used as new
property name:
someObject["-1.5"] = "foo"; // creates key "-1.5" with value "foo"
someObject["4294967296"] = "foo"; // creates key "4294967296" with
value "foo"

By explicetly serving a valid index value to a pre-declared array:
someArray[3] = "foo";
you free the interpreter from the unnecessary checks/transformations
and you get a noticeable productivity gain.

In this concern I don't care too much (actually I don't care at all) if
ECMA specs are saying something other, because this is how it does
really work on any browser I know of.
Will you learn how to quote?

Well, sorry but I used to quote in the way one can see who am I
answering to (if there are several responses) and what am I answering
to:
Poster Name / Nickname wrote:
Quote
My answer
....
and I don't see any reason to change this habit unless some really
serious *logical* reasons will be provided (to fix it right away:
written rules are not one of them ;-)
 
L

Lasse Reichstein Nielsen

VK said:
Rather elegant but requires Object<>Array back and forth casting which
will swallow any productivity difference advantages between of them ?

There is no casting anywhere. In Javascript, arrays *are* objects, and
their numbered properties are just that: object properties. The only
"magic" in arrays are in the internal [[put]] method, which keeps
the "length" property in sync with the numbered properties. A literal
implementation of the ECMAScript specification of objects would use
the same [[get]] method for arrays and non-array objects.
Wow: double speed gain on Array with FF. These are 1-10 seconds speed
gain for application I guess - if you manage to stay within Array only.

Only if the application does nothing but array accesses and takes 2-20
seconds to run.
IE seems rather indifferent but still just a bit quicklier.

That small a difference could easily be within the measuring
uncertainty.
Both Opera and Firefox seems to take extra time when the property is a
string containing a number literal, even when used on an object, not
an array. One can wonder why :)

Was that a rhetorical question? :)
Naturally arr["3"] takes longer because the system is trying to find
first CDATA-named property "1", fails on that and only then it gets
array element with index 3.

That makes no sense. "CDATA" is an HTML type, not something that
exists in Javascript. If you just mean "string", then it's still
an interesting result, since the ECMAScript standard describes all
properties as strings, even array properties. The curious part was
that even on a non-array object, useing "3" as property name takes
longer than using "x", even though there is no reason to treat
numerals different from other property names.

/L
 
T

Thomas 'PointedEars' Lahn

VK wrote:

[Quotation corrected]
Thomas said:
CDATA is a data type specified in SGML/XML and used in DTDs for markup
languages. We are talking about a programming language specification
and its implementation, particularly ECMAScript 3 [1], subsection 11.2.1.

?

JavaScript/JScript Object accepts CDATA literals as property name.

Sorry, but this *is* utter nonsense indeed. You obviously have no idea
what CDATA is. Hint: there is not one reference to it in the ECMAScript
Specification, or any _JS language_ reference for that matter.

We are talking about built-in language objects here, not host DOM
objects where a reference to the CDATA type might be appropriate.
Array index is unsigned 32 bit value
Yes.

which allows you to hold 4294967295 array elements per array- that's one
less than 32 bits can hold: the remaining one is used for the length
value.

With this description, I am not sure we understand each other as it was
meant.

32 bits allow you to store 4294967296 different unsigned states. That is
4294967295 non-zero states plus the zero state. Which is why you could
_theoretically_ hold 4294967296 elements in one Array, where the minimum
element index is 0 and the maximum one is 4294967295. However, since
there has to be a _separate_ `length' property that also can only hold
an unsigned 32-bit integer (range from 0 to 2^32-1 = 4294967295) at the
maximum as well, only 4294967295 elements are allowed and thus only
4294967294 is allowed for maximum index.
By explicetly serving a valid index value to a pre-declared array:
someArray[3] = "foo";
you free the interpreter from the unnecessary checks/transformations

No.

,-<http://www.mozilla.org/js/language/E262-3.pdf>
|
| [...]
| 11.2 Left-Hand-Side Expressions
|
| Syntax
|
| MemberExpression :
| PrimaryExpression
| FunctionExpression
| MemberExpression [ Expression ]
| MemberExpression . Identifier
| new MemberExpression Arguments
|
| [...]
| The production MemberExpression : MemberExpression [ Expression ] is
| evaluated as follows:
|
| 1. Evaluate MemberExpression.
| 2. Call GetValue(Result(1)).
| 3. Evaluate Expression.
| 4. Call GetValue(Result(3)).
| 5. Call ToObject(Result(2)).
| 6. Call ToString(Result(4)).
^^^^^^^^^^^^^^^^^^^^^^^^
| 7. Return a value of type Reference whose base object is Result(5) and
| whose property name is Result(6).

As you can see, if the implementation is standards compliant, all parameters
of the bracket property accessor are converted to String first. And *then*
follows

| 15.4 Array Objects
|
| Array objects give special treatment to a certain class of property names.
| 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 2^32?1.

So in terms of "saving the 'interpreter' work" it would be even more
efficient to always quote all parameters for the bracket property
accessor, thus saving it from type conversion in the abstract internal
ToString operator which is defined as follows:

| 9.8 ToString
|
| The operator ToString converts its argument to a value of type
| String according to the following table:
|
| Input Type Result
| ------------------------------------------------------------------
| Undefined "undefined"
| Null "null"
| Boolean If the argument is true, then the result is "true".
| If the argument is false, then the result is "false".
| Number See note below.
| String Return the input argument (no conversion)
| Object Apply the following steps:
| Call ToPrimitive(input argument, hint String).
| Call ToString(Result(1)).
| Return Result(2).
|
| 9.8.1 ToString Applied to the Number Type
|
| [too much to be quoted here, go read on that yourself]

You have not bothered to read the section of the specification I have
referred to and the other sections it is referring to. Again.
and you get a noticeable productivity gain.

The reasons for this lie elsewhere, it is perhaps due to a not conforming
implementation.
Well, sorry but I used to quote in the way one can see who am I
answering to (if there are several responses) and what am I answering
to:
Poster Name / Nickname wrote:
Quote
My answer
...
and I don't see any reason to change this habit unless some really
serious *logical* reasons will be provided (to fix it right away:
written rules are not one of them ;-)

Your quotes are like this:

| > > User 1 wrote:
| > > [Text of User 1]
| .
| > User 2 wrote:
| > [Text of User 2]
|
| Your text

Expected (and, it appears to me, accepted) is:

| User 2 wrote:
| > User 1 wrote:
| > > [Text of User 1]
| >
| > [Text of User 2]
|
| Your text

Not only that the initial attribution line is to indicate who wrote what, to
allow quotes to be trimmed easily, the quotation character sequence is to
indicate the quotation level, to be able to assign quoted text to a person
easily.


HTH

PointedEars
 
T

Thomas 'PointedEars' Lahn

Lasse said:
VK said:
Naturally arr["3"] takes longer because the system is trying to find
first CDATA-named property "1", fails on that and only then it gets
array element with index 3.

That makes no sense. "CDATA" is an HTML type, not
something that exists in Javascript.

Just to have my daily nitpick: it is an _SGML_ type :)


SCNR
PointedEars
 
L

Lasse Reichstein Nielsen

VK said:
JavaScript/JScript Object accepts CDATA literals as property name.

No, that's confuzing terms. CDATA is a type in HTML documents. In the
DOM, the contents of CDATA sections and attributes are available as
Javascript strings. Objects accept *strings* as property names.

It might be a little pedantic, but its still correct :)
Array index is unsigned 32 bit value which allows you to hold
4294967295 array elements per array-that's one less than 32 bits can
hold: the remaining one is used for the length value.

Yes. (It's not that the last property is used to hold the length
property, as this could be misunderstood to say, just that the length
must be a 32 bit unsigned number and must be able to be one larger
than the largest used array index).
So in case:
someObject["3"] = "foo";
interpreter checks first if the key can be converted into an integer in
the range 0,..., 4294967295

It shouldn't (or needen't) do that according to the ECMAScript
specification. The expressions
someObject["3"]
and
someObject["03"]
access different properties. If someObject is an array, only the first
corresponds to an array element, so "can be converted into an integer"
is imprecise. A more precise way of saying it would be:
if the key is the canonical representation of an unsigned integer
in the range 0 .. 2^32-2...
If it can then someObject is treated as array (if contextually
possible) and its element with index 3 gets value "foo".

There is no "treating like an array". All properties are equal on
objects, arrays or not. Non-array objects are not "treated like
objects" if you use "3" as a property name, an array-objects
are not "treated like" objects when you use "x" - they *are*
objects.

Only when assigning to properties on an array is there a difference,
and only when assigning to a property name that is the canonical form
of an array index or is "length".
If the key cannot be converted into integer or if such integer goes
outside of the 0,..., 4294967295 range then the value is used as new
property name:
someObject["-1.5"] = "foo"; // creates key "-1.5" with value "foo"
someObject["4294967296"] = "foo"; // creates key "4294967296" with
value "foo"

And
someObject["123"] = "foo" // creates key "123" with value "foo"
// *and* if someObject is an array with
// someObject["length"] <= 123, it updates
// someObject["length"] to 124.
By explicetly serving a valid index value to a pre-declared array:
someArray[3] = "foo";
you free the interpreter from the unnecessary checks/transformations
and you get a noticeable productivity gain.

That is a possible optimization an implementation can do. You can keep
"array index" named properties as numbers and not convert the operand
to a string before doing the lookup. It seems most browsers does something
of this sort, even on non-arrays, which accounts for the larger overhead
when using the string "3" as operand of the property access operation.
In this concern I don't care too much (actually I don't care at all) if
ECMA specs are saying something other, because this is how it does
really work on any browser I know of.

Do you have documentation of that? Which browsers do you know of?

/L
 
T

Thomas 'PointedEars' Lahn

Lasse said:
There is no "treating like an array".
Exactly.

All properties are equal on objects, arrays or not.

No said:
[...]
Only when assigning to properties on an array is there a difference,
and only when assigning to a property name that is the canonical form
of an array index or is "length".

Certainly not.
By explicetly serving a valid index value to a pre-declared array:
someArray[3] = "foo";
you free the interpreter from the unnecessary checks/transformations
and you get a noticeable productivity gain.

That is a possible optimization an implementation can do. You can keep
"array index" named properties as numbers and not convert the operand
to a string before doing the lookup.

Where is this backed up by ECMAScript 3 as an allowed optimization for
a compliant implementation?


PointedEars
 
V

VK

Lasse said:
There is no casting anywhere. In Javascript, arrays *are* objects, and
their numbered properties are just that: object properties. The only
"magic" in arrays are in the internal [[put]] method, which keeps
the "length" property in sync with the numbered properties. A literal
implementation of the ECMAScript specification of objects would use
the same [[get]] method for arrays and non-array objects.

Sorry but that's an urban legend greatly dispropaganded in the 3rd
edition of my <http://www.geocities.com/schools_ring/ArrayAndHash.html>
and it will be completely busted in the 4th one I'm hoping to finish
before Christmas. To facilitate the cultural shock some people may
experience :) here a piece of tast cases directly related to the
current OP. You are welcome to put each position into your own
benchmark test.
All comments are inside.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Test Template</title>
<meta http-equiv="Content-Type" content="text/html;
charset=iso-8859-1">

<script type="text/javascript">

var obj = {};
var arr = [];

function init() {
}

function test() {

/**
* Each block below should be uncommented
* separately before testing and commented
* back before moving to the next block
*/


/**
* Both Hashtable (used for Object) and Array
* accept non-ECMA naming compliant literals as property name:
*/
//obj["^^^CDATA^^^"] = "foo";
//arr["^^^CDATA^^^"] = "foo";
//alert(obj["^^^CDATA^^^"]); // "foo"
//alert(arr["^^^CDATA^^^"]); // "foo"


/**
* Array neither counts its properties
* as array elements nor it knows anything
* about them:
*/
//alert(arr.length); // 0

/**
* But Array's Object envelope
* knows about them:
*/
//alert("^^^CDATA^^^" in arr); // true


/**
* Array can hold up to 4294967295 indexed elements
* (which is 32 bit unsigned minus one bit for the length flag).
* This means that the maximum index you can use in array is
* 4294967294
*/
//arr[4294967294] = "foobar";
//alert(arr.length); // 4294967294

/**
* An integer bigger than 4294967294 or lesser than 0
* (so it cannot be used as an array index) turns on
* JavaScript Baby Care mechanics. Instead of simply break the
execution
* with "Invalid array index value" message as any other language would
do,
* interpreter switches the object from Array-mode to Hashtable-mode,
* converts argument from number to string and adds new key to the
hash.
* Naturally array doesn't know about it, exactly as Dr. Jekyll had
nothing
* but to guess what Mr. Hyde this time did.
* Also valuable cycles are being spent for all this marry-go-round.
*/
//arr[4294967294 + 1] = "foobar";
//alert(arr.length); // 0
//alert(4294967295 in arr) // true

/**
* The same as above happens if argument number but not an integer.
* Also valuable cycles are being spent for all this marry-go-round.
*/
//arr[1.5] = "bar";
//alert(arr.length); // 0


/**
* Serving a string index to array turns on
* JavaScript Baby Care mechanics also. First interpreter
* attempts to convert the string into valid index value.
* If it's possible: then the situation gets really ambigious:
* hell does user want to add "33" property or array[33] ?!?
* To cover all holes, interpreter both add new array element [33]
* and new property "33".
* Needless to say that a create amount of cycles goes for this
* thinking and arrangement.
*/
//arr["33"] = "foo";
//alert(arr.length); // 34
//alert("33" in arr) // true


/**
* If string value is not convertable into a valid array index,
* interpreter simply switches object from Array-mode to
* Object-mode and adds new property to the Object envelope.
* Still cycles are being vasted unless you really wanted to add
* new property to your array.
*/
arr["foo"] = "bar";
alert(arr.length); // 0
alert("foo" in arr) // true

/**
* These are all very basics above you need to understand
* clearly before to deal with code benchmarks: otherwise
* they will be one huge unresolved mistery to you.
* And naturally JavaScript Baby Care has absolutely nothing
* to do with Hashtable or Array nature, same way as its typeless
* has nothing to do with String or Number nature.
*/

}

function testIE() {
test();
}

function testFF() {
test();
}

window.onload = init;
</script>

<style type="text/css">
body {background-color: #FFFFFF}
var {font: normal 10pt Verdana, Geneva, sans-serif;
color: #0000FF; text-decoration: underline;
cursor: hand; cursor:pointer}
</style>

</head>

<body>

<noscript>
<p><font color="#FF0000"><b>JavaScript disabled:-</b><br>
<i><u>italized links</u></i> will not work properly</font></p>
</noscript>

<!--[if gte IE 5]>
<p>
<var onclick="testIE()">Test</var>
</p>
<![endif]-->
<![if ! gte IE 5]>
<p>
<var onclick="testFF()">Test</var>
</p>
<![endif]>

</body>
</html>
 
V

VK

Sorry for typo in the testcase I posted before (I had to extract parts
from a bigger sample).

Statements:

obj["^^^CDATA^^^"] = "foo";
arr["^^^CDATA^^^"] = "foo";

must be in the init() function and uncommented.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Test Template</title>
<meta http-equiv="Content-Type" content="text/html;
charset=iso-8859-1">

<script type="text/javascript">

var obj = {};
var arr = [];

function init() {
obj["^^^CDATA^^^"] = "foo";
arr["^^^CDATA^^^"] = "foo";
}

function test() {

/**
* Each block below should be uncommented
* separately before testing and commented
* back before moving to the next block
*/


/**
* Both Hashtable (used for Object) and Array
* accept CDATA literals as property name:
*/
//alert(obj["^^^CDATA^^^"]); // "foo"
//alert(arr["^^^CDATA^^^"]); // "foo"


/**
* Array neither counts its properties
* as array elements nor it knows anything
* about them:
*/
//alert(arr.length); // 0

/**
* But Array's Object envelope
* knows about them:
*/
//alert("^^^CDATA^^^" in arr); // true


/**
* Array can hold up to 4294967295 indexed elements
* (which is 32 bit unsigned minus one bit for the length flag).
* This means that the maximum index you can use in array is
* 4294967294
*/
//arr[4294967294] = "foobar";
//alert(arr.length); // 4294967294

/**
* An integer bigger than 4294967294 or lesser than 0
* (so it cannot be used as an array index) turns on
* JavaScript Baby Care mechanics. Instead of simply break the
execution
* with "Invalid array index value" message as any other language would
do,
* interpreter switches the object from Array-mode to Hashtable-mode,
* converts argument from number to string and adds new key to the
hash.
* Naturally array doesn't know about it, exactly as Dr. Jekyll had
nothing
* but to guess what Mr. Hyde this time did.
* Also valuable cycles are being spent for all this marry-go-round.
*/
//arr[4294967294 + 1] = "foobar";
//alert(arr.length); // 0
//alert(4294967295 in arr) // true

/**
* The same as above happens if argument number but not an integer.
* Also valuable cycles are being spent for all this marry-go-round.
*/
//arr[1.5] = "bar";
//alert(arr.length); // 0


/**
* Serving a string index to array turns on
* JavaScript Baby Care mechanics also. First interpreter
* attempts to convert the string into valid index value.
* If it's possible: then the situation gets really ambigious:
* hell does user want to add "33" property or array[33] ?!?
* To cover all holes, interpreter both add new array element [33]
* and new property "33".
* Needless to say that a create amount of cycles goes for this
* thinking and arrangement.
*/
//arr["33"] = "foo";
//alert(arr.length); // 34
//alert("33" in arr) // true


/**
* If string value is not convertable into a valid array index,
* interpreter simply switches object from Array-mode to
* Object-mode and adds new property to the Object envelope.
* Still cycles are being vasted unless you really wanted to add
* new property to your array.
*/
arr["foo"] = "bar";
alert(arr.length); // 0
alert("foo" in arr) // true

/**
* These are all very basics above you need to understand
* clearly before to deal with code benchmarks: otherwise
* they will be one huge unresolved mistery to you.
* And naturally JavaScript Baby Care has absolutely nothing
* to do with Hashtable or Array nature, same way as its typeless
* has nothing to do with String or Number nature.
*/

}

function testIE() {
test();
}

function testFF() {
test();
}

window.onload = init;
</script>

<style type="text/css">
body {background-color: #FFFFFF}
var {font: normal 10pt Verdana, Geneva, sans-serif;
color: #0000FF; text-decoration: underline;
cursor: hand; cursor:pointer}
</style>

</head>

<body>

<noscript>
<p><font color="#FF0000"><b>JavaScript disabled:-</b><br>
<i><u>italized links</u></i> will not work properly</font></p>
</noscript>

<!--[if gte IE 5]>
<p>
<var onclick="testIE()">Test</var>
</p>
<![endif]-->
<![if ! gte IE 5]>
<p>
<var onclick="testFF()">Test</var>
</p>
<![endif]>

</body>
</html>
 
V

VK

Thomas said:

To Thomas 'PointedEars' Lahn and to anyone who wants to prove its
position by quoting ECMA: this argument is not accepted unless proven
by test (like my position in the previous post is).

Otherwise you're in rather stupid position of a person who's meeting
the Magellan's ship arrival and who's quoting Aristot Earth model to
them to prove that their trip was absolutely impossible so it stays
impossible.

(Please - ECMA writing is not Aristot lore so I'm not a Magellan of any
kind, just a free associattion).
 
R

Richard Cornford

VK said:
Lasse Reichstein Nielsen wrote:
There is no casting anywhere. In Javascript, arrays *are*
objects, and their numbered properties are just that: object
properties. The only "magic" in arrays are in the internal
[[put]] method, which keeps the "length" property in sync
with the numbered properties. A literal implementation of
the ECMAScript specification of objects would use the same
[[get]] method for arrays and non-array objects.

Sorry but that's an urban legend

Which is an urban legend? That there is no casting? There is not. That
Arrays are Objects? They are. That the numbered properties of an array
are object properties? they are. That the only 'magic' is in the
internal [[Put]] method of an Array? Well the internal [[Put]] method is
a specification mechanism, it explains the behaviour it does not
constrain the implementation. Or that a literal implementation of
ECMAScript would use the same [[Get]] method? It would, but
implementations don't have to be literal, they just have to behave as if
they were literal.

People will find it much easier to correct your misconceptions if you
could clearly state what they are instead of making vague references to
wide ranging blocks of text.
greatly dispropaganded in the 3rd
edition of my

Without the ability to pin down and state what you are trying to
disprove it is unlikely that you will achieve anything, except spreading
more confusion and misconceptions.
<http://www.geocities.com/schools_ring/ArrayAndHash.html>
and it will be completely busted in the 4th one I'm hoping
to finish before Christmas. To facilitate the cultural shock
some people may experience :) here a piece of tast cases

It would be better to present all of a test case rather than just a
piece of it as that may enable people to work out what it is exactly
that you are going on about this time.
directly related to the current OP. You are welcome to put
each position into your own benchmark test.
All comments are inside.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Test Template</title>
<meta http-equiv="Content-Type" content="text/html;
charset=iso-8859-1">

<script type="text/javascript">

var obj = {};
var arr = [];

function init() {
}

function test() {

/**
* Each block below should be uncommented
* separately before testing and commented
* back before moving to the next block
*/


/**
* Both Hashtable (used for Object) and Array
* accept non-ECMA naming compliant literals as property name:

ECMA 262 places no restrictions upon the character sequences used as
property names. The only restriction is that only property names that
correspond with the formal definition of an Identifier may be used with
dot notation property accessors. Bracket notation property accessors
have no such restrictions.
*/
//obj["^^^CDATA^^^"] = "foo";
//arr["^^^CDATA^^^"] = "foo";
//alert(obj["^^^CDATA^^^"]); // "foo"
//alert(arr["^^^CDATA^^^"]); // "foo"

100% in accordance with the behaviour specified in ECMA 262.
/**
* Array neither counts its properties
* as array elements nor it knows anything
* about them:

That is too incoherent to convey meaning.
*/
//alert(arr.length); // 0

100% in accordance with the behaviour specified in ECMA 262.
/**
* But Array's Object envelope
* knows about them:

What is an object "envelope"?
*/
//alert("^^^CDATA^^^" in arr); // true

100% in accordance with the behaviour specified in ECMA 262.
/**
* Array can hold up to 4294967295 indexed elements
* (which is 32 bit unsigned minus one bit for the
length flag).

What length 'flag'? do you mean the length property?
* This means that the maximum index you can use in array is
* 4294967294
*/
//arr[4294967294] = "foobar";
//alert(arr.length); // 4294967294

100% in accordance with the behaviour specified in ECMA 262.
/**
* An integer bigger than 4294967294 or lesser than 0
* (so it cannot be used as an array index) turns on
* JavaScript Baby Care mechanics.

Nothing is 'turned on', the behaviour is as specified and applies in all
cases.
Instead of simply break the execution
* with "Invalid array index value" message as any
other language would do,

Well they are not invalid array indexes they are _not_ array indexes so
they re treated as property names when used to add properties to an
object that is also an Array.
* interpreter switches the object from Array-mode to
Hashtable-mode,

Do you have any evidence for any switching? The specified behaviour is
that an Array is an object so it exhibits object behaviour when property
names do not qualify as array indexes.
* converts argument from number to string and adds new key
to the hash.
* Naturally array doesn't know about it, exactly as Dr. Jekyll
had nothing
* but to guess what Mr. Hyde this time did.
* Also valuable cycles are being spent for all this
marry-go-round.
*/
//arr[4294967294 + 1] = "foobar";
//alert(arr.length); // 0

100% in accordance with the behaviour specified in ECMA 262.
//alert(4294967295 in arr) // true

100% in accordance with the behaviour specified in ECMA 262. But I
thought you said that this array object did not know about properties
added with non-array index property names? This array object is
asserting that it has such a property.
/**
* The same as above happens if argument number but not an
integer.
* Also valuable cycles are being spent for all this
marry-go-round.
*/
//arr[1.5] = "bar";
//alert(arr.length); // 0

100% in accordance with the behaviour specified in ECMA 262.
/**
* Serving a string index to array turns on
* JavaScript Baby Care mechanics also.

Nothing is 'turned on' as the behaviour is inherent in the array object.
First interpreter
* attempts to convert the string into valid index value.
* If it's possible: then the situation gets really ambigious:
* hell does user want to add "33" property or array[33] ?!?

They are equivilent.
* To cover all holes, interpreter both add new array
element [33]
* and new property "33".

When they are both the same thing the interpreter cannot do 'both'. Only
one property is added to the object.
* Needless to say that a create amount of cycles goes
for this
* thinking and arrangement.
*/
//arr["33"] = "foo";
//alert(arr.length); // 34
//alert("33" in arr) // true

100% in accordance with the behaviour specified in ECMA 262.
/**
* If string value is not convertable into a valid array
index,
* interpreter simply switches object from Array-mode to
* Object-mode and adds new property to the Object envelope.

So that would be another assertion of 'switching' where none is evident
and 'envelopes' with no explanation or justification for the use of this
made-up term.
* Still cycles are being vasted unless you really wanted
to add
* new property to your array.
*/
arr["foo"] = "bar";
alert(arr.length); // 0
alert("foo" in arr) // true

100% in accordance with the behaviour specified in ECMA 262.
/**
* These are all very basics above you need to understand
* clearly before to deal with code benchmarks: otherwise
* they will be one huge unresolved mistery to you.
<snip>

What exactly is a sequence of demonstrations of arrays behaving in
accordance with the formal specification supposed to demonstrate?
Particularly, what it is supposed to demonstrate that suggests that
Lasse's comments are an urban legend?

All this does is suggest that you are still suffering form fundamental
misconceptions about the nature of javascript.

Richard.
 
L

Lasse Reichstein Nielsen

Thomas 'PointedEars' Lahn said:

That doesn't disagree with how I meant it to be understood :)

When a property (i.e., a name/value pair) has been created on an
object, it doesn't matter if it is on an array or a non-array
object. The [[Get]] method is the same in both cases, as is
[[HasProperty]] and [[Delete]], which are all you can do with the
existing property.
[...]
Only when assigning to properties on an array is there a difference,
and only when assigning to a property name that is the canonical form
of an array index or is "length".

Certainly not.

From section 8.6.2:

| For native objects the [[Get]], [[Put]], [[CanPut]],
| [[HasProperty]], [[Delete]] and [[DefaultValue]] methods behave as
| described in described in sections 8.6.2.1, 8.6.2.2, 8.6.2.3,
| 8.6.2.4, 8.6.2.5 and 8.6.2.6, respectively, except that Array
| objects have a slightly different implementation of the [[Put]]
| method (section 15.4.5.1).

Only the [[Put]] method on arrays makes arrays different from other
objects wrt. property access, and only when putting a value.

Reading the algorithms for [[Put]] on non-array objects and on array
objects, the array-version only acts differently if the property name
is "length" or if it is an array index (a numeral that is the
canonical form of an integer in the range 0 .. 2^32-2).

So, yes, all properties on objects are equal, arrays or not. The only
difference is what happens when you assign to a property of an array
with a name that is an array index or is "length".

Where is this backed up by ECMAScript 3 as an allowed optimization
for a compliant implementation?

That would be:

| 5.2 Algorithm Conventions
| The specification often uses a numbered list to specify steps in an
| algorithm. These algorithms are used to clarify semantics. In
| practice, there may be more efficient algorithms available to
| implement a given feature.

An implementation doesn't have to follow the algorithms from the
ECMAScript standard, it just has to give the same result. As such,
all semantics preserving optimizations are allowed.

/L
 
L

Lasse Reichstein Nielsen

[arrays are objects, their elements are object properties, only the
[[Put]] method on objects makes it differ from other objects ...
according to ECMAScript]
Sorry but that's an urban legend

It's what the ECMAScript standard specifies. It is all you can assume
about ECMAScript implementations in general. Specific implementations
might have certain characteristics that you can discover and use, e.g.,
an underlying implementation that is more or less efficient for numbers
than for strings. But it's not something you can rely on between
implementations.

....
var obj = {};
var arr = [];
....

All examples are consistent with ECMAScript, and what I said, so it is
only the timing of the implementation that can be discussed.

I agree that your description probably matches the internal model of
both IE, Mozilla and Opera's Javascript engines, to some extend.
There are differences between them that are probably also important.


If timing is really important, and has been shown to be so, not just
guessed at, I recommend fixing on a fe, browsers and testing
there, and then allowing the code to be slower on unknown or unexpected
browsers. Premature optimization is the root of all evil.

/L
 
T

Thomas 'PointedEars' Lahn

Lasse said:
Thomas 'PointedEars' Lahn said:

That doesn't disagree with how I meant it to be understood :)

When a property (i.e., a name/value pair) has been created on an
object, it doesn't matter if it is on an array or a non-array
object. The [[Get]] method is the same in both cases, as is
[[HasProperty]] and [[Delete]], which are all you can do with the
existing property.

And how does the first paragraph of the Array object specification fit in?
There is clearly either replacing or additional property handling defined
for those objects, see below.
[...]
Only when assigning to properties on an array is there a difference,
and only when assigning to a property name that is the canonical form
of an array index or is "length".

Certainly not.

From section 8.6.2:

| For native objects the [[Get]], [[Put]], [[CanPut]],
| [[HasProperty]], [[Delete]] and [[DefaultValue]] methods behave as
| described in described in sections 8.6.2.1, 8.6.2.2, 8.6.2.3,
| 8.6.2.4, 8.6.2.5 and 8.6.2.6, respectively, except that Array
| objects have a slightly different implementation of the [[Put]]
| method (section 15.4.5.1).

Only the [[Put]] method on arrays makes arrays different from other
objects wrt. property access, and only when putting a value.
[...]

The specification seems to produce a contradiction by itself here.
In section 8.6.2 in restricts the difference to the [[Put]] method,
in section 15.4 it specifies "special treatment to a certain class
of property names."
That would be:

| 5.2 Algorithm Conventions
| The specification often uses a numbered list to specify steps in an
| algorithm. These algorithms are used to clarify semantics. In
| practice, there may be more efficient algorithms available to
| implement a given feature.

An implementation doesn't have to follow the algorithms from the
ECMAScript standard, it just has to give the same result. As such,
all semantics preserving optimizations are allowed.

ACK


PointedEars
 
V

VK

Richard said:
100% in accordance with the behaviour specified in ECMA 262.

I'm not arguing with you any more. There are reasons to argue only if
the final aim is to find the true between each other arguments. It's a
vasted time if any fact is accepted if, and only if, it fits to the
books of canon.

Honnest the God I did not plan to make a trolling thread here - I
really wanted to find the most productive solution for my methods.
Unfortunately I have to conclude that I'm on my own in that as everyone
else is using wrong model, that gives totally wrong benchmark
predictions and totally wrong explanations (or no explanation at all)
to the benchmark results. That would be like asking someone who's using
flat model of Earth for an advise of the best way from Europe to China
through America.

"The great tragedy of science - the slaying of a beautiful hypothesis
by an ugly fact."
T.H. Huxley
 

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

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,043
Latest member
CannalabsCBDReview

Latest Threads

Top