Numeric Equates

PowerBASIC allows you to refer to numeric constants by name.  Be aware that equates have global scope; that is, they are visible throughout your program.  Unlike variables, you can use an equate on the left side of an assignment statement only once, and only a constant value (or a simple variable expression) may be assigned to it.  If an expression is used, all parts of the expression must consist of constants, numeric equates; bitwise operators like AND, OR; and NOT; the arithmetic operators +, -, *, /, and \, and the relational operators >, <, >=, <=, <>, =; and the CVQ function.  For example, the following are all legal equate definitions:

%X = 1

%Y = 1 + 1

%Z = %X * %Y

%Q = (1& OR 2&) + (NOT 0)

%R = (%Q <> 100&)

%S = CVQ("DemoOnly")

A value must be assigned to each equate before it is referenced, even if that value is zero.  If you fail to define an equate, an error will be generated during compilation.  When assigning a value to an equate, the line of code is never executed. Numeric equates must be created outside of any SUB, FUNCTION, METHOD, or PROPERTY.  Numeric equates are global, and may be referenced anywhere in the module.  For readability, we suggest placing equates at the top of your code.

You can also use equates to reduce the incidence of "magic numbers" in your programs.  Magic numbers are mysterious values that mean something to you when you first write a program, but not when you come back to it six months later.  Equates are particularly well suited for making programs more readable.  For example, consider an array to track chess pieces.  If we define:

%MAXPIECES = 32
%NPARAM    = 3

%NTYPE     = 1

%RANK      = 2

%FILE      = 3

%KING      = 1

%PAWN      = 2

…we can then define an array of pieces and make statements like the following:

DIM piece(1:%MAXPIECES, 1:%NPARAM)

piece(1, %NTYPE) = %KING

piece(1, %RANK)  = 4

piece(1, %FILE)  = 1

This sets up a 32 x 3 array for piece information.  The first element is the type of unit, the second and third give its current position on the board.  Note how much more readable this is than:

DIM piece(1:32, 1:3)

piece(1, 1) = 1

piece(1, 2) = 4

piece(1, 3) = 1

We could achieve a similar effect by using comments, but there is no way to ensure that when the program changes, the comments will be updated.  Using equates reduces the need for comments.

Besides being more readable, equates allow us to easily change a program by changing only the definition of a single equate, rather than changing every occurrence of a particular value.  For example: say you run a preschool, and you want to keep track of some data that depends on how many kids you have.  Furthermore, you have to print out reports each week.  Rather than type the number in several places, only to have to change it every week, you can assign the number to a constant.

%NUMKIDS = 28

Then, you can use the constant, %NUMKIDS, throughout your program.

' Calculate income; the enrollment fee is $85 a week;

' Parents pay whether their kids miss days or not

income% = %NUMKIDS * 85

' Calculate actual attendance

attend% = %NUMKIDS - absent%

' Calculate how much the lunches cost per kid; note the

' use of another constant for cost; it may vary too!

perkid% = %LUNCHCOST / attend%

' Calculate net profit per kid after paying for lunches (you'd

' actually have far more overhead than this, but we'll keep it simple)

net% = (income% - perkid%) / %NUMKIDS

' and so on

If your enrollment stays stable, you still have a program that is much easier to follow.  Moreover, if your enrollment changes, you only need to change the constant assignment statements to run a revised program.  Think of the time you will save - enough to take the kids on an extra field trip.

You might also want to assign the value of an equate conditionally, using the #IF metastatement.  For example:

%BIGCLASS = 1

#IF %BIGCLASS

  %NUMKIDS = 40

#ELSE

  %NUMKIDS = 20

#ENDIF

Equates make SELECT statements more readable too:

SELECT CASE piece(x, %NTYPE)

  CASE %KING

    { process king moves }

  CASE %PAWN

    { process pawn moves }

  CASE %QUEEN

     ...

END SELECT

This code will continue to make sense when you return to it after a long absence.

Numeric equates may be assigned a specific integer-class if the literal value has a type-specifier appended.  For example:

%MAX_BYTE      = 255?

%MAXIMUM_INT   = 32767%

%MAXIMUM_DWORD = &HFFFFFFFF???

%MAXIMUM_LONG  = &H7FFFFFFF&

%MINIMUM_LONG  = &H80000000&

Numeric equates which are derived from an equation are pre-calculated by PowerBASIC during the compilation process, to ensure that unnecessary calculations are eliminated from the executable code.  If this optimization was not performed, PowerBASIC code would need to perform the same calculation every time the equate was used in the code.  Examples of numeric equates derived from expressions follows:

%WHATEVER1 = 10

%WHATEVER2 = (%WHATEVER1 * 3) + 1

%DEBUG     = -1&

%RELEASE   = NOT %DEBUG

%DEMO      = %RELEASE AND (NOT %DEBUG)

During compilation the actual numeric value of %WHATEVER2 is pre-calculated as 31, and the values of %RELEASE and %DEMO are calculated from the value of %DEBUG.  Note that operators like AND and OR work as bitwise operators, rather than logical operators, in numeric equate assignments.

Duplicate definitions of both numeric and string equates are permitted by PowerBASIC, provided the actual equate content is identical.  If the content is not identical, a compile-time Error 468 ("Duplicate Equate") will occur.

 

See Also

Constants and Literals

Defining Constants

Built-in numeric equates

String Equates

Built-in string equates