Previous | Index | Next 

[HOWTO] Optimize Boolean expressions using PostProcess pragmas

Note: this article only applies to conversions to VB.NET.

Many VB6 projects contain Boolean expressions that could be easily optimized. VB Migration Partner doesn’t automatically perform these optimizations, because most of them are related to the programming style of each developers. This article shows how easy it is to implement such optimizations, by means of PostProcess pragmas.

Important note: like all substitutions based on regular expressions, there is a small probability that the techniques discussed in this article might suffer from false matches and, therefore, might produce invalid VB.NET code. Ensure that you add these pragmas to your VB6 code only after you have checked that the conversion works well and be prepared to remove these pragmas if you notice that they produce invalid VB.NET code.

  1. Comparisons with True and False

    some VB6 developers like to explicitly compare a Boolean variable with True or False, as in this example:
            Dim x As Integer, res As Boolean, res2 As Boolean
            ' ...
            If res = True And res2 = False Then x = 0
    Explicit comparison of a Boolean variable with True or False adds a little overhead, which can be avoided by re-rewriting the expression as follows:
            If res And Not res2 Then x = 0
    Here are the PostProcess pragmas that do the trick:
    '##  REM Convert "condition = True" into "condition" inside If and ElseIf statements
    '##  PostProcess "(?<=\n[ \t]*)(?<key>If|ElseIf)\b(?<pre>.+)\b(?<cond>\S+)[ \t]*=[ \t]*
                     \bTrue\b(?<post>.+)\bThen\b", "${key}${pre}${cond}${post}Then", True
    '##  REM Convert "condition = False" into "Not condition" inside If and ElseIf statements
    '##  PostProcess "(?<=\n[ \t]*)(?<key>If|ElseIf)\b(?<pre>.+)\b(?<cond>\S+)[ \t]*=[ \t]*
                     \bFalse\b(?<post>.+)\bThen\b", "${key}${pre}Not ${cond}${post}Then", True
    The condition can appear also inside Do Until, Do While, Loop Until, Loop While, and While statements, thus we need two more PostProcess pragmas:
    '##  REM Convert "condition = True" into "condition" inside Do, Loop, and While statements
    '##  PostProcess "(?<=\n[ \t]*)(?<key>(Do|Loop)[ \t]+(While|Until)|While)\b(?<pre>.+)\b
                      (?<cond>\S+)\s*=\s*\bTrue\b", "${key}${pre}${cond}", True
    '##  REM Convert "condition = False" into "Not condition" inside  Do, Loop, 
             and While statements
    '##  PostProcess "(?<=\n[ \t]*)(?<key>(Do|Loop)[ \t]+(While|Until)|While)\b(?<pre>.+)\b
                      (?<cond>\S+)\s*=\s*\bFalse\b", "${key}${pre}Not ${cond}", True
  2. Not keyword in Do While and Loop While statements

    If a Do While or Loop While statement is followed by a condition that is prefixed by the Not keyword, you can drop the Not keyword and transform the statement into Do Until or Loop Until, respectively. For example, the following code
            Do While Not res
                ' ...
            Loop
    can be transformed into:
            Do Until res
                ' ...
            Loop
    This is the PostProcess pragma that can perform this substitution for you:
    '## REM Convert  "Do While Not condition" loops into "Do Until" loops
    '## PostProcess  "(?<=\n[ \t]*)(?!.*\b(And|Or|Xor)\b)(?<key>Do|Loop)[ \t]+While[ \t]+Not
                      [ \t]+(?<cond>.+)", "${key} Until ${cond}", True
    Notice that the regex pattern fails if the condition contains an And, Or, or Xor operator. This check is necessary to avoid to mistakenly match an expression such as this:
            Do While Not res And x = 10
    Keep in mind that you can’t apply this optimization to While…End While loops, unless you have converted them to Do…Loop blocks. (This article explains how to do it by means of PostProcess pragmas.)

  3. Not keyword in Do Until and Loop Until statements

    If a Do Until or Loop Until statement is followed by a condition that is prefixed by the Not keyword, you can drop the Not keyword and transform the statement into Do While or Loop While, respectively. For example, the following code
            Do Until Not res
                ' ...
            Loop
    can be transformed into:
            Do While res
                ' ...
            Loop
    The PostProcess pragma that can perform this substitution is as follows:
    '## REM Convert  "Do Until Not condition" loops into "Do While" loops
    '## PostProcess  "(?<=\n[ \t]*)(?!.*\b(And|Or|Xor)\b)(?<key>Do|Loop)[ \t]+
                     Until[ \t]+Not[ \t]+(?<cond>.+)", "${key} While ${cond}", True
  4. Assigning True/False to a variable in a If...Then...Else block

    A common coding pattern among developers is to use an If…Then…Else block to assign True or False to a Boolean variable. For example, consider the following VB6 code:
            Dim x As Integer, res As Boolean, res2 As Boolean
            ' ...
            If x <> 0 Then
                res = True
            Else
                res = False
            End If			
    
            If x > 10 And x < 20 Then
                res2 = True
            Else
                res2 = False
            End If
    It is evident that it can be simplified (and optimized) as follows:
            res = (x <> 0)
            res2 = Not (x > 10 And x < 20)
    Creating a regular expression pattern that allows you capture and transform the If…Then…Else block isn’t a trivial task, also because we must account for single-line If statements:
    '## REM Convert  "If test Then val=True Else val=False" blocks into  "val=(test)"
    '## PostProcess  "(?<=\n[ \t]*)If[ \t]+(?<cond>.+?)[ \t]+Then[ \t]*\r?\n[ \t]*\b
                      (?<var>(Return\b|\S+[ \t]*=))[ \t]*True[ \t]*\r?\n[ \t]*Else[ \t]*\r?\n
                      [ \t]*\k<var>[ \t]*False[ \t]*\r?\n[ \t]*End[ \t]+If[ \t]*\r?\n", 
                     "${var} (${cond})\r\n", True
    
    '## REM same as  previous one, but works for single-line IF statements
    '## PostProcess  "(?<=\n[ \t]*)If[ \t]+(?<cond>.+?)[ \t]+Then[ \t]+
                      (?<var>(Return\b|\S+[ \t]*=))[ \t]*True[ \t]+Else[ \t]+\k<var>[ \t]*
                      False[ \t]*\r?\n", "${var} (${cond})\r\n", True
    
    '## REM Convert  "If test Then val=False Else val=True" blocks into "val=Not (test)" 
    '## PostProcess  "(?<=\n[ \t]*)If[ \t]+(?<cond>.+?)[ \t]+Then[ \t]*\r?\n[ \t]*\b
                      (?<var>(Return\b|\S+[ \t]*=))[ \t]*False[ \t]*\r?\n[ \t]*Else[ \t]*\r?\n
                      [ \t]*\k<var>[ \t]*True[ \t]*\r?\n[ \t]*End[ \t]+If[ \t]*\r?\n", 
                     "${var} Not (${cond})\r\n", True
    
    '## REM same as  previous one, but works for single-line IF statements
    '## PostProcess "(?<=\n[ \t]*)If[ \t]+(?<cond>.+?)[ \t]+Then[ \t]+
                     (?<var>(Return\b|\S+[ \t]*=))[ \t]*False[ \t]+Else[ \t]+\k<var>[ \t]*
                     True[ \t]*\r?\n", "${var} Not (${cond})\r\n", True
    Notice that the patterns that follow account both for variable assignements and for the Return keyword used to return a value from a function (such Return keyword is used by VB Migration Partner if possible).

  5. Assigning different values to a variable inside an If...Then...Else block

    Another common coding pattern is to use an If…Then…Else block to assign one of two possible values to the same variable, as in these examples:
            If x <> 0 Then
                y = x + 10
            Else
                y = 20
            End  If
    
            ' single-line variant
            If x <> 0 Then y = x + 10 Else y = 20
    There is a more concise – though not necessarily more efficient – way to perform the same assignment:
            y = IIf(x <>  0, x + 10, 20)
    If you are interested in performing this substitution automatically, you can use the following two pragmas:
    '## REM Convert  "If test Then var=value1 Else var=value2" 
             into "var = IIF(test, value1, value2)"
    '## PostProcess  "(?<!\bEnd[ \t]+)\bIf[ \t]+(?<cond>.+?)[ \t]+Then[ \t]*\r?\n[ \t]*\b
                      (?<var>(Return\b|\S+[ \t]*=))[ \t]*(?<v1>[^\r\n]+)\r?\n[ \t]*Else[ \t]*
                      \r?\n[ \t]*\k<var>[ \t]*(?<v2>[^\r\n]+)[ \t]*\r?\n[ \t]*End[ \t]+
                      If[ \t]*\r?\n", "${var} IIf(${cond}, ${v1}, ${v2})\r\n", True
    
    '## REM same as  previous one, but works for single-line IF statements
    '## PostProcess  "(?<!\bEnd[ \t]+)\bIf[ \t]+(?<cond>.+?)[ \t]+Then[ \t]+
                      (?<var>(Return\b|\S+[ \t]*=))[ \t]*(?<v1>[^\r\n]+)\bElse[ \t]+
                      \k<var>[ \t]*(?<v2>[^\r\n]+)\r?\n",
                     "${var}  IIf(${cond}, ${v1}, ${v2})\r\n", True
    For your convenience, we have gathered all the pragmas shown in this article into a single text file, which you can download here. You can add the project: prefix in front of each pragma to extend their scope to the entire project, you can store theme in a *.pragmas file to easily share them among multiple projects, or you can use a PreInclude pragma to include them in selected VB6 source files.

     

 

Previous | Index | Next