When writing complex expressions whose result is a boolean, the macros compiler will generate compiled code that tries to skip parts of the expression (hence the name shortcut) if the result of the expression would not be changed by the values of the remainder of the calculations.
How the Compiler Evaluates Boolean Expressions
Consider for example the case of the and operator:
if bOne and bTwo and bThree
// do something
endif
It is clear that if bOne is false, the entire expression will be false, regardless of the value of bTwo and bThree. So the compiler generates code that is equivalent to the following:
bTemp = false // bTemp is created by the compiler
if bOne
if bTwo
if bThree
bTemp = true
endif
endif
endif
if bTemp
// do something
endif
Similarly, for the or operator:
if bOne or bTwo or bThree
// do something
endif
It is clear that if bOne is true, then the entire expression will be true, regardless of the value of bTwo and bThree. So the compiler generates code that is equivalent to the following:
bTemp = false // bTemp is created by the compiler
if bOne
bTemp = true
else
if bTwo
bTemp = true
else
if bThree
bTemp = true
endif
endif
endif
if bTemp
// do something
endif
Of course, this also works with more complex combinations of and and or operators.
How to take Advantage of Shortcut Boolean Evaluation
The above looks a lot more complex than necessary, but this is done behind the scenes when the macro is compiled, without the need for you to get involved. The reason why you need to be aware of this compiler optimization is that you can use it to your advantage to speed up the execution of macros.
To take advantage of shortcut Boolean evaluation, whenever a Boolean expression involves more than one condition, you should order these as follows (these guidelines are the same whether the expression contains and, or or a combination of both):
1.First, any simple Boolean variables. These get evaluated fast and their value can help determine if the following, possibly more time-consuming, expressions need to be evaluated.
2.Second all calls to functions that do not involve access to the databases (see point 3).
3.Any calls to functions that involve access to the database. These are basically any function that checks to see if there is a holiday on a given date (such as HolidayOfListOnDate) or look for a translation (such as some cases of EvalToken).
Let's consider a concrete example. The following loop condition is arranged in the worst possible way; the time consuming call to the holidays database is done first even though the whole expression might be false if bIsFinished is true. :
while HolidayOfListOnDate('a', nRunDate) ->
and (YearOf(nRunDate) == n_ScriptYear) ->
and (not bIsFinished)
The optimal way of writing this expression is as follows:
while (not bIsFinished) ->
and (YearOf(nRunDate) == n_ScriptYear) ->
and HolidayOfListOnDate('a', nRunDate)
When the expression is rewritten as above the first check that is done is whether the bIsFinished variable is true, which is a quick call. If it is true then the macros interpreter does not need to evaluate the 2 other conditions and in a loop that is repeated many times for every day of a diary, this can lead to a considerable speed improvement.
Topic 173965, last updated on 18-Apr-2020