Wednesday, July 8, 2009

Dumb mistakes.

Here are a couple of mistakes I make after a long day of coding. Can you spot the errors?

1. Stack Overflow


public class Person
{
private var _name : String;

public function get name() : String
{
if ( name == null ) name = "anonymous";
return _name;
}

public function set name( value : String ) { _name = value };
}


The problem: run this code and you'll get an output panel full of "stack overflow" errors. Why? Well, take a closer look at the getter method. It's supposed to return the value of private member "_name". But the first statement in the method refers to "name," not "_name" (note the underscore). _name is the private member; name is the getter method.

When the first statement executes, it tests to see if THE OUTPUT OF THE GETTER METHOD ITSELF is equal to null. Remember, when you type the name of a getter method by itself, you're really just using a syntactic sugar. "name" is really "name()." So what I'm doing in the first statement is similar to this:


function foo() : Number
{
if ( foo() == null ) trace( "x is equal to null" );
}


The call foo() in the first statement calls the function foo, which has a call to foo in the first statement, which calls foo... and so on. An infinite recursive loop.

In the previous example, I can remove the loop by simply adding underscores to "name":

bad: if ( name == null ) name = "anonymous";
good: if ( _name == null ) _name = "anonymous";

Now name is not calling itself; it's referring to a private member called _name.


2. Null Envy


var herName : String;
var flower : Sprite;
var sheLovesMe : Boolean;
var herAge : Number;
var kisses : int;

if ( herName == null ) herName = "Lisa"; //works like a charm

if ( flower == null ) flower = new Sprite(); //works like a charm

if ( sheLovesMe == null ) sheLovesMe = false; //error

if ( herAge == null ) herAge = 18; //error

if ( kisses == null ) kisses = 0; //error


The problem here is that Booleans and numbers types can NEVER be set to null. They don't accept null as a value; nor can they be compared to null.

Once you define a Boolean, it is automatically set to false. (You can later change its value to true.) There's no such thing as a Boolean with no value, though you can set a Boolean to undefined.


var iLikeCheese : Boolean; //note: not explicitly set to a value
trace( iLikeCheese ); //false


You also can't set or compare a Number to null. Unset numbers are set by default to NaN, which is short for "not a number." However, you can't do this:

if ( herAge == NaN ) herAge = 18; //error

Instead, you have to do this:

if ( isNaN( herAge) ) herAge = 18; //works like a charm

ints and uints default to zero. If I'm using an int as a uint -- in other words, if my int should never be set to a negative number -- I sometimes set it to negative one by default. For instance, you can't give a girl a negative kiss, so...


public static const NOT_SET : int = -1;

var kisses : int = NOT_SET;

if ( kisses == NOT_SET ) kisses = 10;


For this reason, I often use ints to store hex-color values. How else should I indicated no color? After all, zero is black. I suppose I could use a uint and define something like this:


public const NO_COLOR : uint = uint.MAX_VALUE; //MAX_VALUE is a built-in constant

var favoriteColor : uint = NO_COLOR;

if ( favoriteColor == NO_COLOR ) favoriteColor = 0xFF0000;


This solution is probably good enough for most simple circumstances, but if I need something more robust and scalable, I create a class:


public class Color
{
public static const NO_COLOR : uint = uint.MAX_VALUE;
private var _color : uint = Color.NO_COLOR;

public function get color() : uint { return _color; }
public function set color( value : uint ) { _color = value; }
public function isSet() : Boolean { return _color == Color.NO_COLOR; }
}

No comments:

Post a Comment