MXMLC’s -define feature allows you to do two things: compile-time constants (as covered previously) and conditional compilation. Both are very useful, so today I’m covering conditional compilation.

Conditional compilation is, thankfully, also simple. All you need to do is surround your code with a compile-time constant:

// Hide the context menu's built-in items in the release version of the app
CONFIG::release {
	var menu:ContextMenu = new ContextMenu();
	menu.hideBuiltInItems();
	this.contextMenu = menu;
}

Here our compile-time constant is CONFIG::release. We must define it as an expression that evaluates to true at compile time. Here are some examples:

Code Included
  • true
  • 1
Code Not Included
  • false
  • 0
Compiler Error
  • null
  • x + y (where x and y are variables)
  • {
  • foo(

So if the compile-time constant evaluates to true, the resulting code will be:

// Hide the context menu's built-in items in the release version of the app
	var menu:ContextMenu = new ContextMenu();
	menu.hideBuiltInItems();
	this.contextMenu = menu;

This is just the above source with the CONFIG::release { and ending } stripped out. I left the indentation and comment in place, though it doesn’t really matter. If the compile-time constant evaluates to false, the resulting code will be:

// Hide the context menu's built-in items in the release version of the app

The whole block from CONFIG::release { through } simply disappears! This is great on many fronts, chiefly optimization and SWF size. On the optimization front there is no faster code than the code that does not exist. This is the ideal way to exclude logging, error checking, and such nice development and debugging code from the final release of the app. On the SWF size front the story is much the same: code that doesn’t exist can’t contribute to the SWF size even a single byte.

One interesting quirk is that the text outside the conditional block must be a compile-time constant and not simply what that constant evaluates to. For example, this will not work:

true {log("literal");}

If you try it, you’ll get the following error from MXMLC:

Syntax error: expecting rightbrace before leftbrace.
 
 			true{log("literal");}
 			    ^

Another unfortunate result of this compile-time definition feature is that it doesn’t allow nearly as much flexibility as C/C++’s #define. Specifically, you can’t make a macro like this C/C++ example:

#define RADTODEG(x) ((x) * 57.29578)

So we end up where we ended up at the end of the last article: an AS3 function that must be (slowly) called. The whole point of a macro in C/C++ is to avoid the function call by inlining its body for improved speed. Sadly, this seems impossible in MXMLC given the limitations discussed above. Chief among them is that you cannot simply use arbitrary text in your define as that would not be a compile-time constant (see the “compiler error” list above). Otherwise we might make a pair of defines like this:

-define=LOG::start,"log("
-define=LOG::end,");"

And use it like this:

LOG::start "hello" LOG::end

This would be replaced and look like this, were C-style #defines allowed:

log( "hello" );

Sadly, they are not. One alternative is to use the C preprocessor as a preprocessing step before your code is compiled, but that tends to get very messy very fast.

In conclusion, conditional compilation goes along with compile-time constants nicely to shift some run-time work forward to compile time. By using this technique we get faster, lighter code. To me, that makes it worthwhile.