Consider this code snippet:

var xml:XML = <outer><inner>null</inner></outer>;
var xmlList:XMLList = xml.inner;
trace(xmlList == null);

What does the trace statement output, true or false, and why?

Well, first, let's stipulate that the "innner" element in the XML object 
contains the String "null". It's not an empty element, for those who might 
think that "null" is interpreted as a literal null.

Second, the expression "xml.inner" returns a non-null XMLList object, which is 
assigned to the variable xmlList. If you were to dereference the xmlList 
variable, say by calling its "length()" method, it would assuredly not throw a 
#1009 null reference error, but rather it would return 1, which is the number 
of child elements of "outer" that have the name "inner". So the "inner" element 
is the only member of xmlList.

So now you have reference to a non-null XMLList of length 1. It seems obvious 
that comparing that reference to null with the equality operator (==) should 
evaluate to false, right?

Well, it doesn't. The expression:

xmlList == null

evaluates to true, and that is what the trace statement outputs in the original 
example.

After spending about 4 hours looking in all the wrong places for a bug that was 
actually caused by this odd little quirk, once I found out what was really 
causing the problem, I thought for sure that it had to be a bug in the 
ActionScript or E4X implementation. After all, it can't be right that a 
non-null object reference is considered equivalent to null, right?

Wrong again. If you read the ASDoc for the equality operator, that's what it's 
supposed to do. In the Flex 3.2 Language Reference, the section on the equality 
operator says:

"If the data types of the operands do not match, the result is false except in 
the following circumstances: 
  ...
One operand is of type XMLList, and either of the following conditions is true: 
     * The length property of the XMLList object is 0, and the other object is 
undefined.
     * The length property of the XMLList object is 1, and one element of the 
XMLList object matches the other operand."

In our case, the length "property" (poor choice of words, since .length would 
return another XMLList) is 1, so the result will be based on a comparison 
between the one element of the XMLList, which is an XML object, and the other 
operand, which is null.

So what does the equality operator doc say about XML objects to non-XML 
operands? It says the result is false unless "one operand is of type XML with 
simple content (hasSimpleContent() == true), and after both operands are 
converted to strings with the toString() method, the resulting strings match."

So here, we do in fact have an XML object, the "inner" node, with simple 
content, i.e. the String "null". And when you convert that XML object to a 
string with the toString() method, you will simply have the string "null". And 
when you convert the OTHER OPERAND, which is null, to a string, you will also 
have "null", and therefore the equality operation will return true.

So there you have it. It's working the way it was designed to work. A null is 
converted to the string "null" for the purpose of an equality comparison. 
Personally, I think it was a poorly thought-out design decision, but hey, what 
do I know? Maybe they had their reasons. I think the language designers should 
have made a separate rule or two to cover cases when one operand is null or 
undefined and the other is not.

And as a side note, if the strict equality operator (===) is used, then the 
expression:

xmlList === null

evaluates to false, as you would expect.


Reply via email to