Advertisement
  1. Code
  2. ActionScript
Code

Fixing Bugs in AS3: Introduction

by
Difficulty:BeginnerLength:LongLanguages:
This post is part of a series called How to Fix Bugs in Flash.
Quick-Tip: Throwing Errors the Clean Way
Quick Tip: How to Debug an AS3 Error #1009

In this tutorial, I’ll describe some of the basic information you need to debug your Flash applications. Finding and resolving errors in your ActionScript is no small task, so this is actually just the first article of a series. In this installment, we’ll take a look at some of the general things you can do to help track down your bugs.


The Different Kinds of Error

First, let’s discuss what an error is. There are three broad categories of errors, in no particular order:

  • Compiler Errors
  • Run-time Errors
  • Logical Errors

In order to differentiate between these, it’s helpful to understand the process of how a SWF is made and presented.

In the process of creating a Flash movie (or application, or whatever you want to call it), you write ActionScript and create graphical assets that are used by the movie. You may use Flash Professional, or Flash Builder and the Flex Framework, or a third-party editor and IDE like FlashDevelop or FDT. In all cases, the work you do to create your movie is known as authoring and the time you spend doing that is referred to as author-time.

At some point, you will want to see the things that you author presented as they would to the end user. Before you can see this, though, the author-time assets (ActionScript, drawings, images, fonts and text, etc) need to be compiled into the SWF that the end user sees. When you hit “Publish” or “Test Movie” in Flash, or “Run” in Flash Builder, you are compiling your SWF. The program you are using to author will take your author-time assets and compile them into a SWF. The time it takes to do this is called compile-time, as in, the things that happen in this stage are said to happen at compile-time.

Finally, you get to run the SWF in the Flash Player and see how it will look and work when presented. This happens in the browser with the Flash Player plugin, or right in Flash Professional when you choose “Test Movie”, or as an AIR application running on the desktop (or mobile device). No matter the specifics of how the SWF is being presented, it is now running and we are now experiencing run-time. The SWF is being executed by the Flash Player, and all of your compiled code and graphics are visible.

Usually, all of this happens for you; if you use Flash Professional, choosing “Test Movie” will compile the SWF and then run it in its own Flash Player. If you use Flash Builder, choosing “Run” will compile the SWF and then launch it in a browser. This three-stage process is generally something that you don’t think about, which is why I’m taking the time to discuss it in detail.

Now, on the to the errors, and how they relate to these stages.

Compiler Errors are errors in your code that pop up at compile-time. There is something so fundamentally wrong with your code that the compiler stops in its tracks and says, “Whoah, if we continue, your SWF will be seriously messed up. I can’t do it. I just can’t.” Well, OK, it’s not normally so melodramatic, but it will bail at the first sign of trouble and make sure you aren’t given the satisfaction of seeing your SWF run before you fix the problems.

These are generally syntax errors — like missing or mis-matched braces — or else type mis-matches; things that a machine can look at and know is wrong. These are errors that you will see in the Compiler Errors panel in Flash Professional.

The Compiler Errors Panel
The Compiler Errors Panel
The Compiler Errors Panel
The Compiler Errors Panel

Run-time Errors are errors that happen while the SWF is running. In this case, the code is syntactically correct, as it made its way past the compiler without errors (we know this because the SWF is running). But the code still has some flaw in it that caused it to run in a way that the Flash Player doesn’t like; it either doesn’t know what to do with this unexpected result or it’s causing an error to let you know that something failed at run-time.

In these cases, you get an official error detailing the problem and at least a general indication of where in your code it occurred. In Flash Professional, you’ll see these when you “Test Movie” in the Output panel.

A run-time Error in the Output Panel
A run-time Error in the Output Panel

Logical Errors are basically errors in how your program is controlled. These aren’t compiler errors; the SWF is compiled and running. These aren’t run-time errors; Flash Player hasn’t thrown up a big error message in your face. Everything is technically correct and working, but they’re not working the way you want them to. Maybe the grid you laid out programmatically has one too many columns, or the shopping cart total is not being calculated correctly, or a user-entered email address is being validated as unacceptable when really it is, or a sequence of images displays in the wrong order.

These are the hardest errors to find, because they can only be found by using the SWF the way it was intended to be used, and comparing the actual results closely with what you expected to happen. And once found, you don’t get any helpful error messages giving you any idea of what went wrong.

Even though we got this far without compiler or run-time error, something is wrong: we're missing a zero on the price.
Even though we got this far without compiler or run-time error, something is wrong: we're missing a zero on the price.

Compiler Errors: Finding the Problem

Compiler Errors are usually the easiest to deal with. That’s because, for one, the compiler stops in its tracks and tells you about the error, and for two, the compiler error itself tells you what’s wrong, tells you the file and line number, and even prints out that line of code for your reference.

Compiler errors show up in the Compiler Errors panel, so lets take a closer look at this particular element of the Flash IDE:

The Compiler Errors Panel, Again
The Compiler Errors Panel, Again

As you can see in the annotated diagram above, each error is listed on its own line. Each line consists of the same basic information. In the first column, you’ll get the file name and line number on which the error was found. In the above example, the error occurs in a class file. If you wrote code directly in the Script panel, then you’ll get something like “Scene 1, Layer 'Layer 1', Frame 1, Line 1” which is the same thing, only for non-text-file-based code.

Knowing where the error happens is useful, but the second column contains information on why the error occurred. The first bit is the error number, which is like an ID. Each type of error gets its own number. This is followed by an textual description of the error. Now, to be fair, Adobe has some rather obtusely worded error descriptions, and in future articles in this series, we’ll try to decipher some of the more common ones so that you can more effectively deal with them. Until then, we can at least learn that the error number is associated with the error description. The text in the description might get customized to present some contextual relevance, like using the variable or function name from your source code, but the general error is tied to the number. For example, Error 1067 is a coercion error, regardless of whether it’s a coercion of a String to a DisplayObject or of an Array to an ExternalInterface.

A complete list of Complier Errors can be found at this page from Adobe’s ActionScript documentation:

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/compilerErrors.html

Some errors are given more thorough explanations on this page.


Compiler Errors: Resolving the Problem

The great thing about compiler errors is that they are pretty easy to find. Not only do they pop up and prevent you from running your SWF, but you can get to the troublesome code very easily from the Compiler Errors panel. Just double-click any error in the panel and the relevant source file will open up, with your cursor on the right line. Now, if you use Flash Professional with an external editor, you will find yourself double-clicking your way into editing the file in Flash Professional. This may be against your reasons for using an external editor, but at least the error finding is usually pretty quick and you can get it done pretty painlessly. Even if you’re using CS5 with the tight Flash Builder integration, double-clicking the error brings up the file in Flash Professional, not Flash Builder. But Flash Builder has its own compiler error panel, which works in much the same way.

The Flash Builder Compiler Errors panel, or the "Problems" panel
The Flash Builder Compiler Errors panel, or the "Problems" panel

At this point, it’s a matter of going to the line of code specified by the error, and fixing it.


Run-time Errors: Finding the Problem

Once you get through the compiler errors, your SWF will be able to run, but at this point you may run into run-time errors. These happen for any number of reasons — again, we’ll be exploring these later in this series — but for now, let’s explore the anatomy of a run-time error. Here is a typical run-time error as displayed while the SWF is running from “Test Movie” in Flash Professional:

The Output panel displaying a run-time error
The Output panel displaying a run-time error

There is potentially going to be a lot of text spit out at you when an error shows up. It may seem a little intimidating initially, but it’s really just two main sections:

The two main sections of the run-time error
The two main sections of the run-time error

As annotated above, the first bit of the error is the description of what happened. Like compile-time errors, each type of run-time error has an error number, which is associated with a short textual description. The description includes an error type as well as a nerd-speak sentence. The error type might be useful for getting a broad sense of what’s going on, but the description is what really tells you the problem. We’ll take a look at an example shortly.

The second main piece is any text following the first bit, called the stack track or call stack and we’ll get deeper into that in the next step.

Like compile-time errors, the textual descriptions leave a bit to be desired. Once you get a handle on what some of the more oft-seen errors mean, though, you’ll have an idea of what’s wrong and will know where to look.

A complete list of run-time errors is documented here, some of which have notes along with them:

http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/runtimeErrors.html


Run-time Errors: Understanding the Stack Trace

Let’s turn to the second main bit of the run-time error, the stack trace. It can range in length anywhere from one line to a finite-yet-very-large number of lines. The purpose of this stack trace is to notify you of where in your code the error occurred.

Each line in the stack trace represents a single function execution. The top-most line names the function in which the error actually occurred; it contains the line of code that blew everything up. The second line in the stack trace names the function that called the function that caused the error. The third line names the function that called the function that called the function in which the error occurred. And…you get the idea. But let’s illustrate it more practically. In the following code, the function third will cause a run-time error by trying to add “nothing” to the display list. However, we don’t call it right away; we start things off by calling the first function, which calls the second function, which in turn finally calls the third function:

If you paste that code in the Script panel of a brand new Flash file, and run it, you see the following error:

Now, we know that the error was due to sending an uninitialized Sprite variable to addChild. The function that actually threw the error (that’s the technical term; when an error occurs, it means that the error was thrown by a specific line of code. I like to think of it as similar to throwing a tantrum) is the addChild method, and so it’s at the top of the list. The next three lines are the functions we wrote, listed most-recent-first. It ends (or begins, depending on how you look at it) with a call to frame1 in the main timeline. This is just the method that kicks off the SWF. If you had a document class set up, you’d see that instead. Since this example just used a script in the first frame, we get frame1.

The point is that calling frame1 ultimately led to an erroneous call to addChild, and you can follow that path of logic by reading the stack trace.

This complete list of function calls might appear to just be a mess of information you don’t need, but there are a number of times when it can help you narrow in on your bug. If the error only occurs in the given function sometimes, you might be able to figure out the problem by tracing the steps taken to get to the function. For example, if there was a bit more interplay in the functions:

The third function might be the most immediate offender, but a close examination would reveal that the second function was the one that actually made s a null value.


Run-time Errors: The Flash Debug Player

An essential tool for the Flash developer is the debug version of the Flash Player. If you don’t have it installed already, you should stop what you’re doing (reading this article) and go download it right now. You will have to restart your browser, as it’s a re-installation of the Flash Player, so bookmark this page first!

Go here to download the appropriate installer:

http://www.adobe.com/support/flashplayer/downloads.html

(Chrome users: read this support note to find out how to override Chrome's built-in Flash Player.)

Once you restart your browser, you won’t notice much different right away. But try it out on this SWF below. First you should see some text indicating your current Flash Player version, including whether it’s the debug version or not. But click on the big button, which is wired to a function that will ultimately throw an error. If you try this out without the debug player, you won’t see anything happen; the error will occur, but will fail silently. If you try it with the debug player, however, you’ll get a rather obtrusive and hard-to-miss error message:

If you’re feeling too lazy to actually install the debug player, or just want verification that you did it right, the error you see should look something like this:

The error window displayed when the debug player is installed.
The error window displayed when the debug player is installed.

Clearly, having the debug player installed is extremely useful for being alerted of errors while testing your SWFs in the browser. As you might imagine (or have already noticed), a SWF that runs just fine from the Flash IDE may find something to complain about when placed in a different environment, like your web server. Imagine that the SWF depends on an XML file to load, but if the path to that XML file is incorrectly resolved on the web server compared to your local dev environment, then a load error will occur. It would certainly be useful to know about this as soon as it happens, rather than being presented with a non-working SWF and no clues.

The downside to the debug player is that it’s rather all-or-nothing; you can’t not debug sites you aren’t developing. That is, if you’re just browsing the web, you will eventually trigger some runtime errors in other SWFs. It’s annoying, and gives you an idea of how little some developers pay attention to their testing process.

As an extra tip, you can easily tell if you have the regular or the debug version of the player by simply right-clicking on any SWF and looking for the “Show Redraw Regions” and “Debugger” options in it:

The Flash Player context menu, when invoked from a debug player
The Flash Player context menu, when invoked from a debug player

Run-time Errors: Permit Debugging

Whether or not you’re viewing run-time errors in the IDE or in the browser, an error is only informative to a point. If you have an error that occurs somewhere in a function, but that function happens to be 20 lines long, you may have a little trouble determining where the offending line of code is.

There are two techniques that have the same results, in that more information is provided in the form of the line of code in question for each function call.

The first technique is more immediate: instead of pressing Command-Return/Control-Enter to test your movie, press Command-Shift-Return/Control-Shift-Enter to debug your movie. This launches the SWF in the Flash Player Debugger, with a debugging session started. When a run-time error is triggered, you’ll bounce back to the Flash IDE (which should reconfigure itself into a debug workspace), and you’ll see a bit more information in the stack trace (note specifically the line numbers added to the output below):

As a bonus, if possible Flash will open up the file responsible for throwing the error, and point to the line in question. Many built-in errors actually occur inside of built-in classes, and so it’s not possible to display that code. But if you’d like to see it in action, try the following code:

...and run it through Debug Movie. Line 7 should be called out.

As we’ve discussed, though, sometimes you need to be testing on a server and through a browser, and the Flash IDE’s debugging facilities are less useful in that regard. With the debug player that we installed in the last step, there is a way to get the line number information included in the run-time error window. This is as simple as enabling a publishing option.

In your Flash document, choose File > Publish Settings… and then click on the Flash tab. Towards the bottom, under the “Advanced” heading, you’ll see a checkbox option for Permit Debugging. Make sure this is enabled, then click “OK.”

The Permit Debugging option in the Flash Publish settings
The Permit Debugging option in the Flash Publish settings

Publish the SWF again, and do what you need to do to run it in your browser again. When a runtime error occurs now, you’ll see the same line number information.

Runtime error in the browser, with line numbers
Runtime error in the browser, with line numbers

You won’t get the ability to jump to the source code, but this line number trick can save you a bunch of time in tracking down errors.

However, be careful to turn of Permit Debugging when you are ready to deploy the SWF to the world. Flash needs to add extra information to the SWF in order to provide the line numbers, and the resulting file size of the SWF is typically 25 - 50% higher than it normally is. It’s a useful debugging tool, but not something you should just turn on for everything everywhere.


Run-Time Errors: Throw Your Own

I mentioned before that it’s possible to throw your own errors (and your own tantrums, but I’ll only describe how to do the former). This can be a helpful technique in debugging. If, for example, you have the following function:

And this function is integral to the functionality of the rest of your movie (presumably we can’t proceed with the XML-driven piece if the XML isn’t parsed), then you might be in for an unpleasant turn of events if the XML object that gets passed into the function a null object, or perhaps doesn’t conform to the structure you expect.

You might therefore consider, in this important function, setting up some checks and, if the checks fail, throw some errors. It can be as simple as this:

Strictly speaking, you would probably want to use the ArgumentError instead of the plain old Error, but the result is essentially the same. If you run this code:

You’ll see a helpful error:

The runtime error
The runtime error

Additionally, you might anticipate that the XML might not be null, but might be edited in a way that does not match the expectations of the parsing function. If you need a node named <entries> to be filled with child nodes named <entry>, but due to human error the XML file looked like this:

Then the parsing would not work. You could protect against this:

And you should get this error:

Another helpful run-time error
Another helpful run-time error

You just might save yourself, or someone else, some time down the line when XML files are edited incorrectly.


Run-Time Errors: Get the Stack Trace Without an Error

Sometimes the stack trace is useful by itself, even if no error has occurred. For instance, every now and then I find myself with a method that is getting called more often than I think it should. If only I could see which other methods are calling it, then I could find where the extra call is coming from.

At first glance, throwing errors would seem a suitable solution. But an error tends to stop an Flash movie in its tracks. If the first error gives me a stack trace, it might prevent the second call from ever happening because the first error prevented it. In these situations, it’s nice to know a little bit more about Error objects.

Most useful is the getStackTrace method, which returns the stack trace as it would be presented were the Error to be thrown. The nice thing, however, is that it does not need to actually be thrown to get this information. So, if you’re simply curious to see the stack trace without throwing errors, you can do something like this:

If you view this in the Flash IDE, the differences between this and a thrown error will be hard to spot; they will both simply output a bunch of information to the Output panel. You might consider embellishing the trace to make it easier to tell the difference. If you’re testing in the browser, though, this code will not present the error window, but simply write to the flash log for your perusal (I’m getting ahead of myself, tracing from the browser is covered in a few steps).


Trace the Heck Out of Everything

Speaking of traces, when it comes to debugging, tracing is the best tool you have available. Sure, Flash Professional and Flash Builder both have debuggers, which let you set breakpoints, step through code, and inspect variables, but quite honestly, I find the quickest route between bug and gathering enough information to fix it is a handful of judiciously placed traces. Traces are useful for debugging both run-time and logical errors, but because we have tools available to get information about run-time errors, traces can be the first line of defense against logical errors.

If I’m debugging a logical error, I usually know about where to focus. The thing that isn’t working is usually localized to a class or two, and usually to a handful of methods and properties. So, within the potential problem areas, I trace the heck out of everything.

More practically speaking, I tend to do the following:

  • Put a trace as the first statement within a function or method, along with an output of any parameters, just to make sure functions are getting called and parameters are what I expect them to be.
  • Trace any variable or property that is used in the function, at least once. If the property is subject to changing during the function, put a trace before and after the potential change.
  • Trace any conditional statements, just to flag which branch you get to.
  • Trace all iterations of loops, usually with some information about the iteration (like the index number and/or the object from the Array relevant to that iteration)
  • If a variable is a complex object, like a Sprite or a Sound, trace several properties of the object

As a stylistic rule, I find it immensely useful to make sure the trace is labeled, too. That is, something like this:

This way, after you’ve added a dozen traces to your code, you can identify the one that says null among all of the other traces more easily.

Additionally, you might even want to prepend the class (and method) name in your traces, just to help further identify the source of each trace.

There are no hard and fast rules for tracing, only my general recommendation to trace everything, even things you think you don’t need to, just to be sure. At this point, a question back to the readers is appropriate: what trace techniques do you rely on? Feel free to start a flame war in the comments.

[Editor's note: Please do not start a flame war in the comments.]


Tracing: Trace from the Browser

Another advantage of the debug player (to the Flash Developer, of course) is the ability to see your traces from the browser, so you can more effectively test and debug a SWF in its natural habitat.

Unfortunately, steps need to be taken to enable this tracing, and I won’t repeat what has been written elsewhere. A search on “flash debug trace” will yield many how-to articles, of which my favorite one is currently at the top of the list on Google, a detailed article on yourpalmark.com that covers various versions of the player on Mac, Windows, and Linux systems.

I will add a tip for Macintosh users. The Console application is mentioned in passing in the linked article, but not really explained or, in my opinion, made use of properly. Console is installed with Mac OS X, and resides in your /Applications/Utilities folder. It’s ideal for displaying log files, which your debug player traces actually are. It’s smart about scrolling to the bottom if you’re already at the bottom, but not scrolling if you’re not. It’s easy to filter and search the log, and I find it indispensable for Flash development.

The Mac's Console application in use for Flash traces
The Mac's Console application in use for Flash traces

The trick, however, is that while Console can open any text file, it only remembers files if they are in the standard log file locations on your system, and if they are .log files. However, the Flash debug player only write traces to a file called flashlog.txt, which is in a non-standard log file location. There is a simple terminal command you can issue to create a symbolic link in the right place:

I wrote more about this trick on my company’s Flash blog here: http://summitprojectsflashblog.wordpress.com/2008/12/17/leopards-console-and-flash-debug-player-traces/


The Flash Debugger

As mentioned earlier, Flash Professional and Flash Builder both provide debugger environments. Personally, I find these of limited usefulness, as I prefer to rely on traces and run-time errors. Also, using the debugger effectively relies on being able to set breakpoints, which can only be (easily) done in code that is open in Flash Professional or Flash Builder. As a matter of personal preference I use TextMate as my editor of choice, which makes setting breakpoints cumbersome. I would be remiss, however, if I did not mention the Flash Debugger in an article about Flash debugging.

Here is a quick tour of the debugging tools you get with Flash Professional. Let’s return to our run-time error producing example from earlier. Paste this code into the script panel of a Flash file:

Before hitting Debug Movie, though, click to the left of the number “5” in the Script panel.

The breakpoints column
The breakpoints column

A red dot will show up in the column, indicating a breakpoint has been set. To remove a breakpoint, simply click it again. With the breakpoint set on line 5 (where second is called inside of first), go ahead and Debug the Movie. Now, we’re expecting the debug workspace to take over because of the error, but if you notice what’s happening, the error hasn’t actually happened (yet). There is a yellow arrow pointing at line 5, indicating that the program execution is paused at our breakpoint. At this point, we have the ability to step through the code one line at a time, and in the process inspect the value of variables, helping us find our bug.

We've hit the breaking point
We've hit the breaking point

Move your attention to the Variables panel, in the lower right corner.

The Variables panel
The Variables panel

Twiddle open the this entry, and you’ll see a nested list of all properties belonging to “this”, which is the main timeline of our SWF. Scroll down and you’ll see “s”, our Sprite variable. You might need to make the panel wider, but the second column should have a value in it, like flash.display.Sprite, indicating that it contains a value.

The Variables panel, with the s variable exposed
The Variables panel, with the s variable exposed

Note that this panel can be used to inspect the value currently in any properties at the time of the pausing of the movie. Also note that while the movie is paused you can double click some of the value fields and type in new values. This will only work on primitive values like Strings and Numbers, but it’s a handy technique to know.

Now, move your eyes up to the Debug Console panel. This is where we can control the pausing and execution of our code. At the top of the panel are a series of buttons. Look for this one:

The Step In button
The Step In button

Click it once, and you’ll notice that the yellow arrow advanced from line 5 to line 7. This indicates what has happened; we’ve fully executed line 5, which involves a call to the function declared on line 7. The next step in our program is to call that function. Check our s variable in the Variables panel. It should still have a Sprite value.

Click the Step In button again. The yellow arrow should point to line 8, where we set s to null. However, if you inspect the Variables panel again, you’ll s still has a value. This is because we’re paused at line 8, but before line 8 actually runs.

Click the Step In button once more, and with the yellow arrow now past line 8, inspect the s property in the Variables panel. Is should now be null. If this example weren’t so simple, we might now have a revelation that the code we just executed is responsible for null-ing our property, which in turn causes our error.

At this point, we’ve satisfied ourselves that this is the cause of the error, so there is no need to keep stepping through code. We can press the green Continue button, which will resume normal execution, and you should then see the error occur.


Wrapping Up

As they said in the 80’s: now you know, and knowing is half the battle. Now you should know some debugging techniques and perhaps learned why some errors show up in different places.

Unfortunately, knowing the facts of debugging is still only half the battle. The other half is much harder to write about in a tutorial. The other half is more about experience and intuition. After you’ve fixed hundreds of bugs, you start to get a sense of what a given error is really about. You also need to know the ins and outs of ActionScript — the rather subtle nuances — in order to make sense of an error that you otherwise would swear shouldn’t be happening.

What I hope we’ve done here is make that first half of the battle easier to get through, so that when you’re facing the real world bugs in your real world projects, you can swashbuckle your way through the second half a little more elegantly.

Finally, be on the look out for a series of debugging Quick Tips. This article provides the generic groundwork that will be referenced by these future Quick Tips. Individual Quick Tips will focus on a very specific, and typically common, type of bug that Flash will throw at you, and how to take care of it when it happens.

We’ll see you there, and thanks for reading.

[Editor's note: Kudos to Yuri Arcurs for his Infuriated Businessman photo, available on PhotoDune.]

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.