back

ActionScript puzzler — The joy of milliseconds

by Charles Bihis

If you’ve been programming for a while, you’ve probably run into some quirks with your programming language. No matter what language you’re using, you’ve undoubtedly encountered strange behavior you didn’t expect — and you’ve had to figure out how to fix it. These idiosyncrasies are known as puzzlers. And most programming languages have a few.

In this article, I present an ActionScript puzzler. I provide a segment of ActionScript code, ask for predictions on what it will produce, and then examine how it actually behaves and why. The results may surprise you. Follow along with me, and see if you can figure out what’s happening before I explain it.

Examining these puzzlers can be both helpful and fun. By becoming more familiar with a language’s eccentricities, you can increase your programming knowledge and become a better problem solver, while having a bit of fun along the way.

The ActionScript code

The following is a simple ActionScript puzzler. Examine the code closely, and see if you can figure out what this code prints:

// declare key dates
var now:Date = new Date();
var birthday:Date = new Date(1940, 06, 27); // Bugs Bunny’s birthday!
// save them as milliseconds since epoch
var nowInMs:int = now.getTime();
var birthdayInMs:int = birthday.getTime();
// get the difference to calculate Bugs’ age in milliseconds
var millisecondsElapsed:int = nowInMs - birthdayInMs;
// sanity check
if (millisecondsElapsed == now.getTime() - birthday.getTime())
{
	trace("What’s up, Doc?");
}

Based on what you know about ActionScript and the code above, can you guess what this code will print? Here are your choices:

  1. Nothing
  2. "What’s up, Doc?"
  3. Throws an exception
  4. None of the above

A closer look

It looks like this code is just trying to calculate Bugs Bunny’s age in milliseconds — from the time he was born until now. To create the code, you first create the key dates. You set now to the current date (as in the date this program is executed), and birthday to his actual birthday. Then you save those times as milliseconds since epoch, so you can easily do some math with these two dates. Next, you need to calculate the difference from Bugs’ birthday (in milliseconds) until now (also in milliseconds), which should give you the total milliseconds elapsed since he was born. For a sanity check, you essentially duplicate the math you did previously: calculate the difference from Bugs’ birthday until now in milliseconds. This should obviously be true, and so you trace “What’s up, Doc?” to the debug console.

The real story

It turns out the answer to the question about what this code prints is: a. Nothing. So how does the trace statement get skipped? That should only happen if the sanity check fails. But the sanity check does exactly what is done earlier in the code — almost. The key error in this code is that there is an implicit narrowing typecast. Can you find it?

Let’s take a look at the description of the Date class in the ActionScript 3.0 Reference for the Adobe Flash Platform. In the documentation for the Date.getTime() method, the following function prototype is defined (see Figure 1):

Figure 1. The getTime method for the Date class.

Date.getTime() returns a number. And that number is stored in an int. In ActionScript, a number uses the IEEE-754 double-precision floating-point specification and therefore can use 53 bits to represent integer values. Because int and uint use only 32 bits, numbers can be used to represent values well beyond the range of the int and uint data types. Because of this implicit typecast, the millisecond time gets narrowed and loses precision. Once you know this, it is easy to see why the sanity check fails. The int variable millisecondsElapsed does not, in fact, store the total milliseconds elapsed since Bugs Bunny was born, but rather, it stores the total milliseconds elapsed since he was born truncated to 32 bits. Therefore, the sanity check fails, the if-statement falls through, and the trace statement never gets executed.

The take away

In other languages, implicit narrowing typecasts cause warnings or even compilation errors, but in ActionScript, they do not. So whenever you are storing or working with numbers, be aware of the size of the numbers as well as the data types floating around. Implicit casts do occur in ActionScript (and often, in any language), but implicit narrowing casts will go unnoticed by the compiler, and you might not notice them either. But now you know to look for them.

Summary

If you want to learn more about ActionScript, check out the ActionScript 3.0 Reference for the Adobe Flash Platform. It is extremely well documented and is a great resource for anyone who works in ActionScript in any capacity. For more puzzlers like this one, visit my blog.

‹ Back


Charles Bihis is a computer scientist at Adobe Systems. He works on Internet technologies.