Watch out! ActionScript Bumps Below

Tuesday, October 26. 2010

Speed Bump AheadWhen reading through ActionScript code I frequently see two ActionScript mistakes that are likely to cause runtime misbehavior and confusions. Sometimes thing do not appear at first glance what you might think at the beginning. However both ActionScript bumps can easily be driven around. 


ActionScript Bump #1: A String is not a Boolean

Check out this code. In which cases will you jump into the if clauses?

var myString:String = null;
if (myString) {
  // String is null - will you jump in here?
}

What do you think? Will you jump into the if clause in this case? Yes? Correct! If a String is null, Action Script interpretes a String as a boolean false in boolean statements. Fine, just what we've expected. Let's check the next case:

var myString:String = "";
if (myString) {
  // String is not null - will you jump in here?
}

OK, what do you believe in this case? Of course, the content of the variable is not null. So we will not jump into the clause... MEEEP! Wrong! A string with a length of zero is also interpreted as false. In ActionScript a string will only be interpreted as boolean true in case it contains at least one character.

I saw this in a couple of place spread all over our code. The bad thing was that unit tests usually tested for actual string values so the error were detected later at runtime. However such errors can easily be avoided by establishing the following guideline:

In conditional expressions, always compare your variables against values unless the type of the variable is boolean.

This is not only true for strings, but also for integers, numbers and so on. This rule simply makes your code much more readable and you'll avoid misunderstandings and errors. In addition a boolean variable should express its boolean nature through its naming anyway - thats why UI components have an enabled flag instead of an enable flag.

So always make it clear and readable what you want to do. Write

if(myString == null)

and

if(myString == null || myString="")

and you will make it immediately clear to readers what you really want to achieve. In case you just specify the string variable alone as shown above, you'll never make a clear statement whether you did this by intention or not.

ActionScript Bump #2: Casting Classes

Assuming that we have two incompatile classes SourceClass and TargetClass - what's the difference between these two code fragments?

public function castFunc1(param:Object) {
  var target:TargetClass = TargetClass(param);
  trace(target.toString());
}

public function castFunc2(param:Object) {
  var target:TargetClass = source as TargetClass;
  trace(target.toString());
}

public function callerFunc(source:SourceClass) {
  castFunc1(source)
  castFunc2(source)
} 

The difference is that the two first functions may produce different errors in case they are called with incompatible types.

The first function will throw an implicit coercion error (#1067, in Java this would be a ClassCastException) in line 2. Just as we would expect. Everybody can easily find the error by looking up the line number in the produced stack trace and it's immediately clear what happened - an object of the wrong type was passed to castFunc1.

The situation is different with the function castFunc2. In this case you won't get an implicit coercion error, but a null pointer exception in line 8. By looking just at the function you are not able to figure out what happened immediately as there are two possible causes. The obvious cause is that someone has passed null to the function, so the call of toString() causes the null pointer exception. Most people will start seeking the root cause in this direction. However you must also consider the behavior of the as operator used in line 7. This operator converts the type of a variable to the specified type, unless the type of the variable does not match the specified target type. In this case the as operator returns null and therefore causes the null pointer exception in line 8.

Now consider you have a much more complex code example and the target variable from line 7 is used later in the code or passed to other functions. This makes it unnecessarily hard to maintain the code.

So take care, when you use which method to case a source type to a target type. In most cases you probably want to use the first notation as shown in line 2. Don't use the as operator unless you are sure that you want to assign null in case of incompatible types.

Hope this reminds you to look twice at code next time you read such statements and avoid similar pitfalls. In case you have other ActionScript traps on your mind I will be very happy to read about what I forgot to mention or about what I was not aware yet in a comment from you below.


Trackbacks


Trackback specific URI for this entry
    No Trackbacks

Comments


    #1 Larry Maccherone on 10/27/10 at 07:18 PM [Reply]
    *You guideline says, "In boolean expression, always compare your variables against values unless the type of the variable is not boolean."

    I think you meant to say, "In conditional expression, always compare your variables against values unless the type of the variable is boolean." (drop the "not")

    or more tersely, "Only use boolean values for "if" statements and other conditionals."

    In the dynamic language world, it's fairly common to rely upon the distinction between truthy and falsish. Once you know the behavior, it's usually not a problem but I think defensively like you and prefer conditionals to evaluate to booleans.
    #1.1 Carsten Schlipf on 10/27/10 at 10:14 PM [Reply]
    *Oops! Of course you are right. Thank you very much for pointing that out.
    #2 Mike on 05/16/11 at 06:33 AM [Reply]
    *This kind of confused me as well, thanks Larry.

Add Comment

HTML-Tags will be converted to Entities.
Standard emoticons like :-) and ;-) are converted to images.
E-Mail addresses will not be displayed and will only be used for E-Mail notifications.

To prevent automated Bots from commentspamming, please enter the string you see in the image below in the appropriate input box. Your comment will only be submitted if the strings match. Please ensure that your browser supports and accepts cookies, or your comment cannot be verified correctly.
CAPTCHA