开发者

Interesting AS3 hash situation. Is it really using strict equality as the documentation says?

开发者 https://www.devze.com 2023-01-01 04:28 出处:网络
AS3 Code: import flash.utils.Dictionary; va开发者_如何学Cr num1:Number = Number.NaN; var num2:Number = Math.sqrt(-1);

AS3 Code:

import flash.utils.Dictionary;
va开发者_如何学Cr num1:Number = Number.NaN;
var num2:Number = Math.sqrt(-1);
var dic:Dictionary = new Dictionary( true );
trace(num1); //NaN
trace(num2); //NaN
dic[num1] = "A";
trace( num1 == num2 ); //false
trace( num1 === num2 ); //false
trace( dic[num1] ); //A
trace( dic[num2] ); //A

Concerning the key comparison method... "The Dictionary class lets you create a dynamic collection of properties, which uses strict equality (===) for key comparison. When an object is used as a key, the object's identity is used to look up the object, and not the value returned from calling toString() on it."

If Dictionary uses strict equality, as the documentation states, then how is it that num1 === num2 is false, and yet dic[num1] resolves to the same hash slot as dic[num2]?


The description given by Adobe is neither exact nor correct to be honest, but it is simpler and covers most cases.

You should try the following:

for (var key:* in dic) trace(getQualifiedClassName(key));//will give you 'String'

this behaviour is true for Array and Object as well.

As a rule of thumb: int stays int and any other key is converted to its string representation (including boolean and float values, as well as null and undefined).

The Dictionary class is different in that it does not convert non-primitive objects to String, but uses them as a key directly. They way of handling all other values is "inherited" Object if you will.

Basically, an Object consists of 2 hashes, one for string and one for integer keys. And the Dictionary adds another hash, probably simply using the objects memory address as integer key.

edit: Not really an answer to the actual question, but a point I want to explain in detail, in response to Triynko's comment:

Hacky? You mean, making it work in a way it's not designed to work? Well... since it's not designed to handle 64-bit integers, of course it's a hack. But 64-bits is 64-bits, whether they're interpretted as an integer or floating point.

Using 64 Bit floats to represent 64 Bit ints is already a bad idea, because semantically, it's completely wrong (you can usually expect problems to arise from this kind of misuse).

But then using their String representation as key (which implicetely happens if you use a float as key) is plain suicide:

var f1:Number = 1000000000000003000000000.0;
var f2:Number = 1000000000000002000000000.0;
trace(f1 == f2);//false
trace(String(f1) == String(f2));//true ... kabooooom

You will have a hard time determining, when 2 64 bit ints will collide, since the prequisite is that the string representation of their values interpreted as floats must be equal. Also, different player versions might have different string conversion of floats, as may alternative runtimes such as LightSpark. I really wouldn't wanna rely on this. This yields the kind of bugs that seem to come out of nowhere, when there's enough data to cause collision. And you will not enjoy tracking them down.

Also, float keys perform worse, since they have to be converted to strings before used for hash look up. If you are really so concerned about size, then you'll have to transmit the data as 64 bit int and convert it to a hex String on flash side only.
None the less, I would point out, that many people are extremely happy using XML or JSON, which has far worse overheads.

Bandwidth and any other hardware resources are cheap. Developement is expensive. You should write your apps to be maintainable and robust, otherwise they cost you more in the long run.

greetz
back2dos


I'm afraid you've tripped over something pretty tricky here. Dictionary works as advertised in the sense that it uses object identities for keys, and does not test objects by value. And in most cases, that works out to the same thing as using strict equality, because in most cases two references to the same object are strictly equal to each other.

The wrinkle is that the AS3 specification has a special case: all comparisons with NaN are considered false by definition - even comparisons between NaN and itself (which is what your sample code is doing). There is even a compile-time warning to the this effect if NaN appears explicitly in the comparison. Also, there are other special cases for some other primitives like 'true' and 'undefined'.

It should be easy to see what's going on if you try a different test value:

import flash.utils.Dictionary;
var num1:Number = Number.POSITIVE_INFINITY;
var num2:Number = 1 / 0;
var dic:Dictionary = new Dictionary( true );
trace(num1); // Infinity
trace(num2); // Infinity
dic[num1] = "A";
trace( num1 == num2 ); // true!!
trace( num1 === num2 ); // true!!
trace( dic[num1] ); //A
trace( dic[num2] ); //A

That might seem odd depending on what languages you're used to, but all it means is that when you create two different references to infinity, AS3 doesn't give you two different objects whose value is infinity, it gives you two references to the same infinity object. Hence the references are strictly equal and they key to the same value. And using NaN instead of Infinity works the same way in every respect, except the part where you compare the value to itself - when it returns false due to NaN being a special case.

0

精彩评论

暂无评论...
验证码 换一张
取 消