This discussion to this point has focused on the mechanics of how conditional
compilation enables you to selectively include and exclude parts of your code
from the compiled version of a project. Now the focus changes to some applications
of these concepts. What follows is hardly an exhaustive list of all the possibilities,
but it should at least suggest some ways to use the preprocessor to your advantage.
Using Debug Mode
Conditional compilation makes it easier to remove debugging tests from your
code prior to building a release version of a project. Rather than having to manually
search and remove (or comment out) tests that may be scattered in multiple modules,
you can place your debug code in conditional compiler blocks:
Dim BuggyVariable as String
‘ ... processing occurs
#If TESTING = 1 Then
‘ see if THIS is where BuggyVariable blew up
MsgBox "Current value of BuggyVariable" " &
åBuggyVariable
#End If
Naturally, you don’t want this to appear in a released product. The key
is to define a constant that will be True only when you are debugging, and False
otherwise. Visual C++ includes a predefined compiler constant that serves just
such a purpose, but Visual Basic requires you to create your own "Debug
mode" constant. Recall that there are three ways to define a compiler constant.
You could define
#Const TESTING = 1
in every module with debug code, and then wrap your tests in the following:
#If TESTING Then
#End If
Of course, this requires you to manually alter each module so that
TESTING is no longer defined as 1 when it is time to build a release. One
of the reasons to use conditional compilation in the first place is to cut down
on that kind of drudgery. Therefore, defining the constant via
#Const probably isn’t the best choice unless your debugging tests
are confined to a single module.
Defining a Public compiler constant, either via the Project Properties dialog
box or on the command line, defines a constant for the entire project. Of course,
if you use the Project Properties dialog box, you must remember to change the
value of TESTING (for example,
TESTING = 0) before building your release. This approach has the advantage
of leaving you with only one place to make the change. Still, it is possible to
forget, especially if you don’t visit the Project Properties dialog box
regularly. This approach is less risky than having to track down
#Const in multiple source files, but there is still a chance that you will
release a project that includes your debug code.
What about the command line? Because you have to explicitly define your Public
compiler constant with the /d switch before beginning each debug session, this
is less convenient than setting the constant with the Project Properties dialog
box. However, it also means that you’re extremely unlikely ever to ship
a version of a project with your debug tests accidentally enabled.
This raises another issue, however: What happens to a conditional compiler
test when a compiler constant is undefined? If you leave the conditional tests
in place after eliminating the definition of a constant, you might expect to see
some kind of preprocessor error message or warning. In fact, you won’t get
one.
Recall that preprocessor constants are treated as Variants. If a Variant hasn’t
been initialized, it has the value Empty. Now, assume that the
RELEASEMODE constant in this example has not yet been defined:
#If Not RELEASEMODE Then
MsgBox "But I thought this code wouldn’t be compiled!"
#End If
In this case, the message box will appear. A Variant containing Empty is treated
as 0, and Not 0 evaluates to True. This means that the message box pops up even
if you haven’t assigned a value to RELEASEMODE.
Because you can’t rely on a compiler warning or preprocessor error message
to inform you of your mistake (there is no Option Explicit for compiler constants),
it is a good idea to take this default behavior into account when you code your
tests to avoid surprises. Always test the compiler constant used to wrap your
debug code for a non-zero value. (That is, never rely on a test that reduces to
"MYCONSTANT = 0".) If you use the command line switch to define
your debug compiler constant, this will make it impossible to accidentally compile
your debug tests into a release.
From a mechanical standpoint, there is nothing more to know about the process
of conditional compilation. After you understand the rules for defining and testing
constants, all that is left is to dream up new ways to apply them. The rest of
this chapter suggests a few ideas to get you started.
Comparing Algorithms
If you are not sure which algorithm is best suited to a procedure, implement
the ones you want to compare in a conditional block. For example:
#Const SortMethod = 1
#If SortMethod = 1
‘ Insertion Sort
#Else If SortMethod = 2
‘ Bubble Sort
#Else If SortMethod = 3
‘ QuickSort
‘ #Else If etc.
#End If
The quantity and state of the data it manipulates may affect the performance
of an algorithm. Insertion sorts are fast with small lists, for example, but performance
deteriorates as the size of the list increases. If a list is already nearly sorted,
a bubble sort can be quite fast.
Conditional compilation to support different algorithms makes it easier for
you to test different approaches to programming problems. Depending on the completeness
of your implementation, you may also find it useful to be able to adapt your program
to the demands of different data sets just by changing the value of a compiler
constant and recompiling.
Feature Sets
The same body of code can support different combinations of features. You may
want to use the same interface for a database program, for example, but employ
it with different data engines. Using conditional compilation, you could produce
separate versions of your program for DAO, RDO, and
ODBC.
Unlike the database scenario, which requires selecting one approach from among
competing alternatives, you can also take an additive approach. If you add fax
support to your program, but you only want it to be included in the releases 2.0
and up, you can still produce a 1.0 EXE from your source, as follows:
#If ReleaseNumber >= 2 Then
‘ fax support
#End If
Just make sure that you specify #Const ReleaseNumber =
1 when you need to generate a 1.0 copy of your program. It is no match
for a full-blown version control system, but conditional compilation can serve
as a limited VCS.
Client Specific
If you provide the same program to multiple clients who require slightly different
features, you can implement these features in a common body of code by wrapping
the client-specific features in conditional compiler blocks that compare a constant
to the client name:
#If ClientName = "Clinton" Then
‘ ingenious code that cripples the Republican party,
‘ except for that pesky Whitewater bug
#End If
#If ClientName = "Dole"
‘ ingenious code that cripples the Democratic party,
‘ except for that annoying 1996 bug
#End If