Preprocessor ASSERTS in ActionScript

Tags:

Unlike most other computer languages, when ActionScript code fails, it fails silently. If my code sends an undefined argument to a function, there is no crash, no alert message, nothing scary.

Overall, this is a good thing. If my live swf hits a bug, it might work just fine, no one is the wiser and life goes goes on blissfully unaware.

This behavior has a downside, however. The bug that is ignored now might cascade into a serious problem later -- in the next frame or in some code far away from the source of the problem. And I'm left scratching my head trying to figure out the original source of the problem in my code. The appearance of the problem and the source of the problem may be far apart.

Instead, I want code failures to be noisy rather than silent, but only during development. I need the ability to build a release version and a development version of the product. The development version will have extra debugging code, and it doesn't matter if the swf is a little extra bulky and slow. The release version, however, should be lean -- no performance or footprint hit.

So how do you do this and what does it look like?

I'm an old C++ guy, and the thing I miss the most from the C++ development environment is the preprocessor. The preprocessor made it easy to create separate debug and release versions of the product. The Flash dev environment does not come with a preprocessor. Using ANT and a C preprocessor, however, you can make it work. (I use Eclipse/FDT. It should also work with FlashDevelop.)

I'll explain the details of how I set it up in another article. Really, there is more than one way to do it. I use a C preprocessor. There are Java preprocessors also. These might work better. My point is that you can probably figure out a way that works for you. The details are not that interesting.

What's more interesting is what it looks like in the code and how it helps speed development. For me, the key is the preprocessor macro ASSERT.

Note: This is not really a new thing. MTASC seems to support the ASSERT macro natively. I like the Flash IDE and don't use MTASC, so I'm not sure. My goal here is to demonstrate how adding asserts to your code will speed development, not to show you some new thing invented by me.

The quickest way to understand the usefulness of ASSERT is to look at some code:

// function from a class
public function setPoints(pts:Array):void
{
  ASSERT(pts != undefined);	
  ASSERT(pts.length == 3);
		
  ASSERT(Dbg.hasProps(pts[0], ["x", "y", "z"]));	
  ASSERT(Dbg.hasProps(pts[1], ["x", "y", "z"]));	
  ASSERT(Dbg.hasProps(pts[2], ["x", "y", "z"]));	
		
  ASSERT(pts[0].z >= 0);
  ASSERT(pts[1].z >= 0);
  ASSERT(pts[2].z >= 0);
  ASSERT(pts[0].z <= 0xFF);
  ASSERT(pts[1].z <= 0xFF);
  ASSERT(pts[2].z <= 0xFF);
		
  // Make a copy of the array and a copy of each point.
  _corners = new Array();
  for (var i:int = 0 ; i < 3 ; i++){
    var pt:Object = pts[i];
    var newPt:Object = {x: pt.x, y: pt.y, z: pt.z};
    _corners.push(newPt);				
  }
  _corners.sortOn("z", Array.NUMERIC);
}

The asserts are verifying that the argument fits a number of criteria. If any of these conditions are not true, an error message with the as file name and line number will appear in the trace window.

I've created a mine field in my code. Ideally, if the code misbehaves in the slightest way, if it does not act that way I think it should, it will immediately blow up and I will know exactly where the bug is.

Note: This works with AS2 and AS3 code.

The ANT build creates a separate directory tree for the debugging version and populates it with the debugging version of the the as files. The debugging version of the above file looks like this:

// function from a class
public function setPoints(pts:Array):void
{
  pub.connectedpixel.debug.Debug.assert(pts != undefined,"G:\\FlashProjects\\Library\\as3\\Flash-ClassPaths\\ConnectedPixel_Main\\preproctmp\\com.connectedpixel.pixel.morph.Triangle3D.as",51);	
  pub.connectedpixel.debug.Debug.assert(pts.length == 3,"G:\\FlashProjects\\Library\\as3\\Flash-ClassPaths\\ConnectedPixel_Main\\preproctmp\\com.connectedpixel.pixel.morph.Triangle3D.as",52);
  pub.connectedpixel.debug.Debug.assert(Dbg.hasProps(pts[0], ["x", "y", "z"]),"G:\\FlashProjects\\Library\\as3\\Flash-ClassPaths\\ConnectedPixel_Main\\preproctmp\\com.connectedpixel.pixel.morph.Triangle3D.as",54);	
  pub.connectedpixel.debug.Debug.assert(Dbg.hasProps(pts[1], ["x", "y", "z"]),"G:\\FlashProjects\\Library\\as3\\Flash-ClassPaths\\ConnectedPixel_Main\\preproctmp\\com.connectedpixel.pixel.morph.Triangle3D.as",55);	
  pub.connectedpixel.debug.Debug.assert(Dbg.hasProps(pts[2], ["x", "y", "z"]),"G:\\FlashProjects\\Library\\as3\\Flash-ClassPaths\\ConnectedPixel_Main\\preproctmp\\com.connectedpixel.pixel.morph.Triangle3D.as",56);	
  pub.connectedpixel.debug.Debug.assert(pts[0].z >= 0,"G:\\FlashProjects\\Library\\as3\\Flash-ClassPaths\\ConnectedPixel_Main\\preproctmp\\com.connectedpixel.pixel.morph.Triangle3D.as",58);
  pub.connectedpixel.debug.Debug.assert(pts[1].z >= 0,"G:\\FlashProjects\\Library\\as3\\Flash-ClassPaths\\ConnectedPixel_Main\\preproctmp\\com.connectedpixel.pixel.morph.Triangle3D.as",59);
  pub.connectedpixel.debug.Debug.assert(pts[2].z >= 0,"G:\\FlashProjects\\Library\\as3\\Flash-ClassPaths\\ConnectedPixel_Main\\preproctmp\\com.connectedpixel.pixel.morph.Triangle3D.as",60);
  pub.connectedpixel.debug.Debug.assert(pts[0].z <= 0xFF,"G:\\FlashProjects\\Library\\as3\\Flash-ClassPaths\\ConnectedPixel_Main\\preproctmp\\com.connectedpixel.pixel.morph.Triangle3D.as",61);
  pub.connectedpixel.debug.Debug.assert(pts[1].z <= 0xFF,"G:\\FlashProjects\\Library\\as3\\Flash-ClassPaths\\ConnectedPixel_Main\\preproctmp\\com.connectedpixel.pixel.morph.Triangle3D.as",62);
  pub.connectedpixel.debug.Debug.assert(pts[2].z <= 0xFF,"G:\\FlashProjects\\Library\\as3\\Flash-ClassPaths\\ConnectedPixel_Main\\preproctmp\\com.connectedpixel.pixel.morph.Triangle3D.as",63);
		
  // Make a copy of the array and a copy of each point.
  _corners = new Array();
  for (var i:int = 0 ; i < 3 ; i++){
    var pt:Object = pts[i];
    var newPt:Object = {x: pt.x, y: pt.y, z: pt.z};
    _corners.push(newPt);				
  }
  _corners.sortOn("z", Array.NUMERIC);
}

You can see that the file name and line number are embedded in every assert call. The code is ugly, but that's ok; this code is not intended for human viewing. It is automatically generated and the Flash compiler uses it to build the debug version.

The ANT build populates the release directory tree with code that looks like this:

// function from a class
public function setPoints(pts:Array):void
{
  //Assert(pts != undefined);	
  //Assert(pts.length == 3);
		
  //Assert(Dbg.hasProps(pts[0], ["x", "y", "z"]));	
  //Assert(Dbg.hasProps(pts[1], ["x", "y", "z"]));	
  //Assert(Dbg.hasProps(pts[2], ["x", "y", "z"]));	
		
  //Assert(pts[0].z >= 0);
  //Assert(pts[1].z >= 0);
  //Assert(pts[2].z >= 0);
  //Assert(pts[0].z <= 0xFF);
  //Assert(pts[1].z <= 0xFF);
  //Assert(pts[2].z <= 0xFF);
		
  // Make a copy of the array and a copy of each point.
  _corners = new Array();
  for (var i:int = 0 ; i < 3 ; i++){
    var pt:Object = pts[i];
    var newPt:Object = {x: pt.x, y: pt.y, z: pt.z};
    _corners.push(newPt);				
  }
  _corners.sortOn("z", Array.NUMERIC);
}

This code is not bulked up. When building the release version, I switch the classpath to look in this directory tree instead of the debug tree. Also, when I give clients a copy of the code, I give them this code. The assert calls are preserved as comments, so if anyone else makes changes to the code, I can take that version and easily resurrect my assert calls.

Whether the asserts are left in the code peranently is optional. On the downside, they do bulk up the source code and make it possibly harder to read. On the upside, when I reuse the code in the future, I continue to get the protection.

BTW, this is similar to the use of asserts in Unit Testing. Like preprocessor asserts, unit testing asserts also verify the sanity of values and conditions. But they are contained in separate test classes that are included only when running unit tests. Preprocessor asserts run all the time in the development version.

Unit testing is more methodical and probably better at finding problems. I hate to admit it, but I've been too lazy to follow the unit testing approach. One of these days I will, maybe, possibly.

But this is not an either-or thing. Unit testing and preprocessor asserts can both exist in a project.

I'll give the macro code for the assert file and the ant file later. I gotta go get dinner.

Comments

Cool, just what I was looking for. But I have no C++ experience (not enough anyway) and have hardly ever used ANT. Did you ever post the macro code and the ant file? Or could you send it to me? It would be really really useful ;)

all the best!

very good article, thanks very much

christian louboutin sale

christian louboutin

very good article, thanks very much

christian louboutin sale

christian louboutin

Woow very good niceee

rance industry abuses and denial of care. returned. Toporno film
-erotik film-inndir-şarkisini dinle-justin tv-yükle-full porno indir---konulu porno---liseli kizlar-sexsi-de the country, free land, and even newly-renovated “doctor living communities” that would be guarded for safety. Still, as our own financial meltdown has shown, all the money and property in the wfirikik-yesilcam pornosu-anal sikis-canli sikis--uzun pornolar----full porno indir

-recepivedik3sinemacekimi--kutsaldamacana2idman
xvideos--vidyo---">>günlükfilm-tikla indir-
pornotv
sicak videolar-kvp filistin--kurtlarvadisi filistin-xvideos--vidyo---">günlükfilm---tikla indir--ünlü pornosu---liseli porno--konulu pornolar--ysician isünlü pornosu quoted as saying çok filim hareketler bunlarthat youngerhint pornosu residents and interns are literally “studying the textbookslez porno # providing the largest middle class tax cut for health care in history, reducing premium costs for tens of millions of families and small business owners who are priced out of coverage today. justin izleThis helps over 31 million Americans afford health care who do not get it today – and makes coverage more affordable for many more.

. perilous swiss watches in stock the profits of the replica watches symptomatic dream up houses. designer replica This plant economy, according to Tim Phillips the watch replica writer of Knockoff: The best watch replica precarious bag effect pseudo Rolex watches replica Goods, would represent the world's biggest plan Gucci Wallet-Black GJ-029B-2725 if incarnate were a Louis Vuitton Wallet Monogram Denim named racket. Counterfeiting is replica handbag familiar to report for 7% of cosmos function further Sterling Silver Give Peace a Chance CZ Necklace outlet may equal for admirable Celebrity Inspired Earrings replicas because 10%.A excellent scale fake The Classic CZ Sterling Silver Dream Ring of traded goods, including garments further New Replica 2009 New Tiffany & Co Bracelets20090825032 accessories are sham. additional rolex watches alarming, is the thinking New Replica Tiffany & Co Bracelets tjewelrybracelet085 that these contents chalk up simulated Bedat & CO replica watches for sale goods that may act replica watch as impressed bag or replica watches used on the shape. admit - your body, my body, not