Usually languages just have one way to specify “no value”. Call it null or nil or whatever you’d like, but AS3 and JavaScript have two: null and undefined. Here’s a little bit to help you understand when and why you’ll come across the two as well as some tricky differences between them.

Null is much like it is in C/C++ and Java: the value that specifies that a pointer or reference points to or refers to nothing at all. C/C++ uses memory addresses directly and 0 is always reserved as “null”, which is often defined as NULL:

Point* p = NULL;

Java uses the constant “null” in a similar manner to mean that a reference points to nothing:

Point p = null;

It seems like there really only needs to be one way to say “nothing”, doesn’t it? Well, JavaScript and AS3 are more dynamic languages than C and Java. C and Java don’t have the ability to create Objects on the fly, create dynamic classes, or utilize really dynamic arrays. Some might think these features “magical”, but they’re really just more dynamic. Usually though, AS3 revolves around Objects that can be null, just as in Java:

var p:Point = null;

The null value is applicable to any Object. However, unlike Java, there is an even more universal type in AS3: *. The * type, which really means “untyped”, indicates anything:

var p:* = 5;
p = new Point();
p = "text";

The above variable can refer to anything, not just Objects. It is even possible for that variable to point to undefined. What is undefined? As the name says, it is anything that has not yet been defined. Here are the ways you can generate an undefined:

// Try to index a dynamic Object by a field it doesn't have
var undef1:* = {x=2, y=3}.z;
 
// Try to access an Array by an index it doesn't have
var undef2:* = [2,4,6][100];
 
// Try to access a Dictionary by a field it doesn't have
var undef3:* = (new Dictionary())["x"];
 
// Try to use an untyped field that hasn't been initialized
class MyClass
{
	private var val:*;
	public function MyClass()
	{
		var undef4:* = val;
	}
}

Generally, any access of a dynamic Object by a property it doesn’t have will return undefined.

So why does AS3 have a second “nothing” value? Just because the language is more dynamic does not necessarily mean that there needs to be a second “nothing” value. You could eek by without undefined, but there are some nice things you can do with it when you know what it really means. The crux of this is using the difference between the == and === operators. For a primer, see my previous article. Essentially, you don’t want to allow conversion between null and undefined. Consider the following:

trace(null == undefined);
trace(null === undefined);

The first statement is true since null and undefined are allowed to be converted in type to each other, mind-bending as it may seem. The second is false though as they are different types and therefore not even allowed to be checked for equality. Now let’s apply it to an example of a class representing a dictionary whose values cannot be overwritten once set:

class ImmutableDictionary
{
	private var dict:Dictionary = new Dictionary();
 
	public function store(key:*, val:*): void
	{
		// Check if previously set
		if (this.dict[key] !== undefined)
		{
			throw new Error("Cannot overwrite " + key);
		}
		this.dict[key] = val;
	}
 
	public function retrieve(key:*): *
	{
		return this.dict[key];
	}
}

If we had used the != operator in the store function above we would have had a critical error. Consider this usage:

var id:ImmutableDictionary = new ImmutableDictionary();
id.store("test", null);
id.store("test", 5);

This would allow the overwriting of the value stored for the “test” key. Why? This is what would be going on in more linear form:

var dict:Dictionary = new Dictionary();
 
// dict["test"] is undefined, converts to null, and the if fails
if (dict["test"] != null)
{
	throw new Error("Cannot overwrite " + "test");
}
 
// dict["test"] goes from undefined to null
dict["test"] = null;
 
// dict["test"] is null from the first store() and the if fails
if (dict["test"] != null)
{
	throw new Error("Cannot overwrite " + "test");
}
 
// The assignment is allowed and dict["test"] goes from null to 5.
// We have failed in stopping the overwrite from taking place.
dict["test"] = 5;

There is a very real difference between null and undefined that can manifest itself in many ways throughout your code. This necessitates the usage of the untyped * type, === to differentiate null from undefined, and an even greater sense of care when dealing with dynamic objects such as Array, Object, Dictionary, and XML.