Optimization issues

Code review rules

Optimization issues are code review rules by which you can improve the performance of execution and reduce the memory requirements of your applications.

Dead code detection

Dead code detection is a crucial part of source code optimization. The dead code detection rules are part of the optimization rules of Project Analyzer. They are described on their own page.

String handling

The string handling rules are useful for programs whose performance is limited by the performance of VB's string functions. Read an article on our web site for more tips for optimized string programming.

Len/LenB is faster than = "" or <> "". To check if a string is empty or not, it's quickest to use the Len function. To test for an empty string, use Len(str)=0. To test for a non-empty string, use Len(str)<>0.

In VB 4-6, use the LenB function instead of Len for the same purpose with extra performance. In VB3 and VB.NET, use the Len function. NULLSTR

Literal "" found. The string literal "" is present in your code. If the statement is an assignment, use vbNullString instead of "". vbNullString is a special constant, available in VB4 and later, that speeds up the assignment and subsequent processing of the value. In classic VB, vbNullString is a null pointer (zero integer), the use of which saves some bytes in the executable file. In VB.NET the case is a bit more complex because vbNullString is the equivalent of Nothing. Replacing "" by vbNullString may introduce errors if you use the string variable in an object-oriented way by calling its methods or properties such as s.Length. In this case, stick to "". Note: In comparison statements use Len/LenB(x)=0 rather than x="". NULLSTR

Text comparison used. Text comparison is much slower than binary comparison. For more speed, use Option Compare Binary, vbBinaryCompare (VB 5-6) and CompareMethod.Binary (VB.NET). TEXTCOMP

Dollar would increase performance. Adding $ at the end of a function would increase the speed of execution. Certain functions, like Left, Mid and Right return a Variant that contains a String. The corresponding functions Left$, Mid$ and Right$ return a String. Using the String version makes your program run faster. This rule applies to VB 3-6 code. In VB.NET, there is no performance difference. NO_DOLLAR

Asc/Chr optimization

Unicode function is faster. The wide functions AscW and ChrW/ChrW$ are faster than the Asc/Chr/Chr$ alternatives. VB works internally in Unicode, so the unicode versions run faster. They are not the same functions though. If you're handling ASCII characters from 0 to 127, you're safe to replace Asc with AscW and Chr with ChrW/ChrW$. - This rule applies to VB4 and later. ASC, CHR

Constant available. A constant is available in place of a function call. Use a string constant instead of Chr/ChrW. The available string constants and their ASCII values are: vbNullChar (0), vbBack (8), vbTab (9), vbLf (10), vbVerticalTab (11), vbFormFeed (12), vbCr (13), vbCrLf or vbNewline (13 & 10). vbNewline is faster than vbCrLf. Successive Chr(13) & Chr(10) should be replaced by vbNewline, not vbCr & vbLf. - Instead of a call such as Asc("A"), use a numeric constant such as Const ascA = 65. - These rules apply to VB 4-6. In VB.NET the compiler takes care of optimizing the use of these functions. ASC, CHR

VB.NET optimization rules

Multi-dimensional array found. In VB.NET, jagged arrays (arrays of arrays) are faster to access than multi-dimensional arrays. The .NET compiler optimizes jagged arrays more efficiently. For example, replace Dim myArray(9,8) As Integer with Dim myArray(9)() As Integer. If your array is large or if you access it often, this optimization technique can give you a moderate performance boost. MULTIDIM

Seal for less overhead. Seal your .NET classes and methods when possible. Overridable (= virtual) methods are slower to call. Overridable methods are polymorphic resulting in calling overhead, which is significant if you need to run millions of calls. Remove any unnecessary Overridable keywords from method definitions. If your method has the Overrides keyword, add NotOverridable to seal the method. Note that it's not necessary to seal the Finalize destructor. If you don't intend to inherit from a class, seal the whole class with the NotInheritable keyword. Attribute classes should also be sealed with NotInheritable. SEAL

WithEvents adds overhead. The WithEvents keyword adds overhead to variable access, as .NET implements these variables as properties. Consider removing WithEvents and handling the events via the AddHandler mechanism. The WithEvents syntax may be easier to read, but it slows down your program. WITHEVENTS

Use compound operator. The compound operators +=, -=, ^=, *=, /=, \= and &= (also <<= and >>= in VB.NET 2003) run faster than their regular counterparts in VB.NET. This is mainly true if the leftmost operand includes a property or function call. COMPOUND

CType is slower than DirectCast. Use the DirectCast keyword instead of the CType keyword when you're just casting an object variable to a variable of a different type in .NET. DirectCast can deliver better performance because it never calls methods in the Microsoft.VisualBasic DLL. You should notice the risk of using DirectCast, though. DirectCast can raise a run-time error if the run-time types don't match. In this case, CType may perform type coercion, while DirectCast raises an error. CTYPE

VB 3-6 optimizations

Consider using Image control. A PictureBox uses significantly more memory and system resources than an Image control. While PictureBox has more features, this PictureBox is a potential candidate to be replaced by an Image control. This suggestion applies to VB versions from 3.0 to 6.0. PICTUREBOX

Object variable declared As New. In VB Classic, declaring an object variable As New creates an auto-instantiating variable. Each time you read the contents of the variable, VB first checks if the variable contains an object, and creates one if not. This adds overhead, thus slowing your program down. To achieve better performance, remove the word New from the declaration, and instantiate your variable (Set x = New Class) before it is used. It makes sense to test with 'If x Is Nothing Then' before accessing the variable, to avoid the run-time error 'Object variable not set'. In addition, VB.NET has different semantics for As New. ASNEW

CVDate found, use CDate. The CVDate function has been replaced by CDate since VB4. CVDate returns a Variant, while CDate returns a Date data type. As to their use, CVDate and CDate are identical except for the handling of Null. CVDate(Null) returns Null, while CDate raises an error. This is a possible caveat when replacing CVDate with CDate. CVDATE

Miscellaneous optimizations

Use Binary instead of Random file access. Random file access is significantly slower than Binary access, making file read/write unnecessarily slow. Replace Random with Binary. There is a catch, however. Handling of file position values is different. For random access, it's the record number. For binary access, it's the byte in the file. Thus, check all Get and Put (VB 3-6) or FileGet/FileGetObject/FilePut/FilePutObject (VB.NET) statements. RANDOM

Consider short-circuited logic. In the expressions (x And y), (x Or y), both operands (x, y) are evaluated. Short-circuiting means rewriting this so that when x=False in (x And y), y is not evaluated. The same goes for x=True in (x Or y). This saves CPU cycles, especially if y is a complex expression. In VB.NET, consider replacing And with AndAlso, and Or with OrElse. In VB Classic, consider splitting an If ..And.. condition as two nested Ifs. Short-circuiting If ..Or.. yields more complex code, usable case by case. Risks: Short-circuiting changes the logic. If the second operand calls a function, this call may not execute. Read VB help for differences between And/AndAlso and Or/OrElse. SHORTCIRC

Slow ^ operator found. Raising to a power with the ^ operator is slow when executed in a loop. Replace ^ by one or more multiplications to achieve better performance: i^2 = i*i, i^3 = i*i*i and so on. For a negative exponent, use division: i^(-1) = 1/i, i^(-2) = 1/i/i and so forth. Note that exponents 0 and 1 make no sense since i^1 = i and i^0 = 1. This rule reports integer exponents from -9 to 9. POW

Base address unoptimal. A library project's base address is set to the default value in project options. When loading the library, the operating system tries to load it at this address. If not possible, it relocates the library. Changing this address to another value will help to reduce the likelihood of relocation, thus making the library load faster. The base address affects ActiveX OCX, ActiveX DLL and .NET Class Library/Web Control Library projects. Notice that in .NET projects, different configurations (Debug/Release) can have different base address values. The rule works on the currently selected configuration. BASEADDR

Compilation unoptimized. The compilation settings for a project are set for unoptimized compilation. In VB 5-6, this is due to p-code or unoptimized compilation. Open the Project Options dialog and choose Compile to Native Code and either Optimize for Fast Code or Small Code in the Compile tab. In .NET this problem indicates that compile-time optimizations are disabled. Right-click the project in VS.NET, open the property pages and choose Enable optimizations. You can also enable some advanced optimization techniques using the settings found in these dialog boxes. Notice that in .NET projects, different configurations (Debug/Release) can have different optimization settings. The rule works on the currently analyzed configuration. There are no optimization settings for projects written with VB 3-4.

Comment directive

The comment directive parameter for the rules on this page is OPT. It also applies to the dead code rules.

See also

Problem detection
Code review rules
Dead code detection

Project Analyzer Help