Are AS3 Number Variables Real Objects or Not?

I am confused. Is the Number class really a class, that I can create instances of and expect to have reference semantics etc. like the rest of the classes in ActionScript3?

Given this AS3 code:

var foo : Number = null;
trace("foo="+foo);

The compiler outputs a warning saying “null used where a Number value was expected“, but it does compile. The trace outputs “foo=0“. Hmm, okay then, foo must be an instance of a Number class. If I change the code to have no initializer for foo, like this:

var foo : Number;
trace("foo="+foo);

The output of the trace will read “foo=NaN“, which is as expected, as this is the default value of Number variables.

But wait, this AS3 code:

if (foo == null) {
trace("oops, does not compile");
}

Actually fails compilation. The compiler complains about “Comparison between a value with static type Number and a possibly unrelated type Null“. So, I can assign null to Number, albeit with a warning, but I cannot compare with null. Okay then, foo must then not be a real reference to an object.

But wait again, the documentation says that Number is a “public final class Number“, which extends Object. But I cannot compare instances of it with null. Hugh!?

I think I am actually supposed to use the global function isNaN(), to determine stuff like this. You might be alarmed to hear then, that isNaN() applied on a Number typed variable, which have previously been assigned null, will return false.

September 11, 2008  Tags: ,   Posted in: Programming

8 Responses

  1. Josh Tynjala - September 11, 2008

    Number, int, uint, Boolean, and String are special types. They don’t act like normal Objects. Most importantly, they aren’t nullable. Additionally, they are compared by value rather than by reference.

    var a:Object = {};
    var b:Object = {}

    a == b //false

    var c:Number = 1;
    var d:Number = 1;

    c == d //true

    Additionally, it’s important to know that null, undefined, and 0 may all go through type conversions when you do comparisons or assignment.

    //EXAMPLE 1
    var nullNum:Number = null;
    trace(nullNum) //0

    It is 0 because null gets type converted to work as a Number. That’s why isNaN() fails.

    //EXAMPLE 2
    var zero:Number = 0;
    if(!zero)
    {
    trace(”zero got type converted”);
    }

    This can be tricky when you actually want a nullable value. For instance, the following code works:

    var styles:Object = {color: 0xff0000, alpha: 0.5};
    if(styles.color)
    {
    //if color is defined, do something
    }

    …but what happens when you change the value of “color” to black?

    var styles:Object = {color: 0×000000, alpha: 0.5};
    if(styles.color)
    {
    //the code in this if statement won’t run
    }

    Color is now equal to zero, which is type converted and becomes false in the comparison.

    In short, you’ve discovered a very tricky part of the core types. It is defined as part of the ECMAScript specification, so this stuff is documented somewhere. I’m not sure if Adobe points it out anywhere, though.

  2. Keith Peters - September 12, 2008

    this might help:

    http://livedocs.adobe.com/flash/9.0/main/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Parts&file=00000048.html

  3. shaun - September 12, 2008

    Hi,
    1. var foo : Number = null;
    2. trace(”foo=”+foo);
    Establishes foo is really 0 (with a warning).

    “You might be alarmed to hear then, that isNaN() applied on a Number typed variable, which have previously been assigned null, will return false.”

    1. var foo : Number = null; //So this is really 0, established prior.
    2. trace(”foo=”+foo); //prints 0
    3. isNaN(foo) == false, is correct. // foo is 0, which is a Number.
    The result of isNaN seems reasonable to me.

    However i do see your point about the Number class itself and not being able to test for null. However as you can see above – the Number is never null
    but rather 0.
    I think that probably the compiler should generate an error when you assign null to a type Number rather than just a warning, which would then make it consistent with the conditional testing against null.

    Nice post.

  4. Darren - September 12, 2008

    The way I see it, if the compiler had given you an error instead of a warning when you incorrectly tried to assign null to a special type of object that is non-nullable then you wouldn’t have written this post. For whatever reason, the compiler seems to have silently cast null to Number (0). Maybe this is a deliberate design decision to handle some border cases, hence the warning to make sure that you really did intend to do it? If you get a warning and then choose to ignore it, then you can hardly complain about unexpected results, no?

  5. Theo - September 12, 2008

    5 is Object // => true

    new int(4) // => 4

    5.5.toString() // => “5.5″

    These statements should be quite conclusive, instances of Number are instances of Object. That doesn’t mean that variables typed as Number, int, uint and Boolean work like variables typed as Object, for example you can’t null them.

    But there’s a difference here, “myNumber is Object” tests the value of the “myNumber” variable, whereas “myNumber = null” sets the variable to null. So Number objects are objects, but variables typed Number are not like other variables, but subject to compiler and runtime optimizations.

    Another weird detail, if you want to call a method on a number literal you can’t do

    5.toString()

    because the “.” is considered to be the decimal point, however

    5..toString()

    works fine (because “5.” is the same as “5.0″).

    http://blog.iconara.net/2007/03/16/architectural-atrocities-part-7-some-types-are-less-equal-than-others/

  6. Danny Miller - September 17, 2008

    Great question regarding data types. I actually just wrote a post on my wordpress to answer
    http://k2xl.com/wordpress/2008/09/17/as3-primitives/

  7. Link Post Sunday 09/14 | Mr Sun Studios - September 21, 2008

    [...] and Flex APIs Lack in Quality and Are AS3 Number Variables Objects or Not? by Tech [...]

  8. Tom - March 3, 2009

    I was trying to use a Number in a constructor and have it as an optional parameter, and if it was not specified I wanted it to match the value of one of the other, required, parameters. Since my class could use both positive, negative, and zero as valid values I couldn’t think of a way to accomplish this since Number can’t be set to null.

    I wanted to do:

    public function SomeClass(minVal:Number,maxVal:Number,defaultVal:Number=null) {
    if (defaultVal==null) {defaultVal=minVal;}

    The workaround is to default the parameter to “Infinity” and check against that since Infinity could never be a valid value for my class:

    public function SomeClass(minVal:Number,maxVal:Number,defaultVal:Number=Infinity) {
    if (!isFinite(defaultVal)) {defaultVal=minVal;}

Leave a Reply