Visual Basic Concepts
Optimizing Code
Unless you're doing tasks like generating fractals, your applications are unlikely to be limited by the actual processing speed of your code. Typically other factors — such as video speed, network delays, or disk activities — are the limiting factor in your applications. For example, when a form is slow to load, the cause might be the number of controls and graphics on the form rather than slow code in the Form_Load event. However, you may find points in your program where the speed of your code is the gating factor, especially for procedures that are called frequently. When that's the case, there are several techniques you can use to increase the real speed of your applications:
Avoid using Variant variables.
Use Long integer variables and integer math.
Cache frequently used properties in variables.
Use module-level variables instead of Static variables
Replace procedure calls with inline code.
Use constants whenever possible.
Pass arguments with ByVal instead of ByRef.
Use typed optional arguments.
Take advantage of collections.
Even if you’re not optimizing your code for speed, it helps to be aware of these techniques and their underlying principles. If you get in the habit of choosing more efficient algorithms as you code, the incremental gains can add up to a noticeable overall improvement in speed.
Avoid Using Variant Variables
The default data type in Visual Basic is Variant. This is handy for beginning programmers and for applications where processing speed is not an issue. If you are trying to optimize the real speed of your application, however, you should avoid Variant variables. Because Visual Basic converts Variants to the appropriate data type at run time, operations involving other simple data types eliminate this extra step and are faster than their Variant equivalents.
A good way to avoid Variants is to use the Option Explicit statement, which forces you to declare all your variables. To use Option Explicit, check the Require Variable Declaration check box on the Editor tab of the Options dialog box, available from the Tools menu.
Be careful when declaring multiple variables: If you don’t use the As type clause, they will actually be declared as Variants. For example, in the following declaration, X and Y are variants:
Dim X, Y, Z As Long
Rewritten, all three variables are Longs:
Dim X As Long, Y As Long, Z As Long
For More Information To learn more about Visual Basic data types, see "Data Types" in "Programming Fundamentals."
Use Long Integer Variables and Integer Math
For arithmetic operations avoid Currency, Single, and Double variables. Use Long integer variables whenever you can, particularly in loops. The Long integer is the 32-bit CPU's native data type, so operations on them are very fast; if you can’t use the Long variable, Integer or Byte data types are the next best choice. In many cases, you can use Long integers when a floating-point value might otherwise be required. For example, if you always set the ScaleMode property of all your forms and picture controls to either twips or pixels, you can use Long integers for all the size and position values for controls and graphics methods.
When performing division, use the integer division operator (\) if you don’t need a decimal result. Integer math is always faster than floating-point math because it doesn’t require the offloading of the operation to a math coprocessor. If you do need to do math with decimal values, the Double data type is faster than the Currency data type.
The following table ranks the numeric data types by calculation speed.
Numeric data types | Speed |
Long | Fastest |
Integer | |
Byte | |
Single | |
Double | |
Currency | Slowest |
Cache Frequently Used Properties in Variables
You can get and set the value of variables faster than those of properties. If you are getting the value of a property frequently (such as in a loop), your code runs faster if you assign the property to a variable outside the loop and then use the variable instead of the property. Variables are generally 10 to 20 times faster than properties of the same type.
Never get the value of any given property more than once in a procedure unless you know the value has changed. Instead, assign the value of the property to a variable and use the variable in all subsequent code. For example, code like this is very slow:
For i = 0 To 10
picIcon(i).Left = picPallete.Left
Next I
Rewritten, this code is much faster:
picLeft = picPallete.Left
For i = 0 To 10
picIcon(i).Left = picLeft
Next I
Likewise, code like this . . .
Do Until EOF(F)
Line Input #F, nextLine
Text1.Text = Text1.Text + nextLine
Loop
. . . is much slower than this:
Do Until EOF(F)
Line Input #F, nextLine
bufferVar = bufferVar & nextLine & vbCrLf
Loop
Text1.Text = bufferVar
However, this code does the equivalent job and is even faster:
Text1.Text = Input(F, LOF(F))
As you can see, there are several methods for accomplishing the same task; the best algorithm is also the best optimization.
This same technique can be applied to return values from functions. Caching function return values avoids frequent calls to the run-time dynamic-link library (DLL), Msvbvm60.dll.
Use Module-level Variables Instead of Static Variables
While variables declared as Static are useful for storing a value over multiple executions of a procedure, they are slower than local variables. By storing the same value in a module-level variable your procedure will execute faster. Note, however, that you will need to make sure that only one procedure is allowed to change the module-level variable. The tradeoff here is that your code will be less readable and harder to maintain.
Replace Procedure Calls with Inline Code
Although using procedures makes your code more modular, performing each procedure call always involves some additional work and time. If you have a loop that calls a procedure many times, you can eliminate this overhead by removing the procedure call and placing the body of the procedure directly within the loop. If you place the same code inline in several loops, however, the duplicate code increases the size of your application. It also increases the chances that you may not remember to update each section of duplicate code when you make changes.
Likewise, calling a procedure that resides in the same module is faster than calling the same module in a separate .BAS module; if the same procedure needs to be called from multiple modules this gain will be negated.
Use Constants Whenever Possible
Using constants makes your application run faster. Constants also make your code more readable and easier to maintain. If there are strings or numbers in your code that don’t change, declare them as constants. Constants are resolved once when your program is compiled, with the appropriate value written into the code. With variables, however, each time the application runs and finds a variable, it needs to get the current value of the variable.
Whenever possible, use the intrinsic constants listed in the Object Browser rather than creating your own. You don’t need to worry about including modules that contain unused constants in your application; when you make an .exe file, unused constants are removed.
Pass Unmodified Arguments with ByVal Instead of ByRef
When writing Sub or Function procedures that include unmodified arguments, it is faster to pass the arguments by value (ByVal) than to pass them by reference (ByRef). Arguments in Visual Basic are ByRef by default, but relatively few procedures actually modify the values of their arguments. If you don’t need to modify the arguments within the procedure, define them as ByVal, as in the following example:
Private Sub DoSomething(ByVal strName As String, _
ByVal intAge As Integer)
Use Typed Optional Arguments
Typed optional arguments can improve the speed of your Sub or Function calls. In prior versions of Visual Basic, optional arguments had to be Variants. If your procedure had ByVal arguments, as in the following example, the 16 bytes of the Variant would be placed on the stack.
Private Sub DoSomething(ByVal strName As String, _
Optional ByVal vntAge As Variant, _
Optional ByVal vntWeight As Variant)
Your function uses less stack space per call, and less data is moved in memory, if you use typed optional arguments:
Private Sub DoSomething(ByVal strName As String, _
Optional ByVal intAge As Integer, _
Optional ByVal intWeight As Integer)
The typed optional arguments are faster to access than Variants, and as a bonus, you'll get a compile-time error message if you supply information of the wrong data type.
Take Advantage of Collections
The ability to define and use collections of objects is a powerful feature of Visual Basic. While collections can be very useful, for the best performance you need to use them correctly:
Use For Each...Next rather than For...Next.
Avoid using Before and After arguments when adding objects to a collection.
Use keyed collections rather than arrays for groups of objects of the same type.
Collections allow you to iterate through them using an integer For...Next loop. However, the For Each...Next construct is more readable and in many cases faster. The For Each...Next iteration is implemented by the creator of the collection, so the actual speed will vary from one collection object to the next. However, For Each...Next will rarely be slower than For...Next because the simplest implementation is a linear For...Next style iteration. In some cases the implementor may use a more sophisticated implementation than linear iteration, so For Each...Next can be much faster.
It is quicker to add objects to a collection if you don't use the Before and After arguments. Those arguments require Visual Basic to find another object in the collection before it can add the new object.
When you have a group of objects of the same type, you can usually choose to manage them in a collection or an array (if they are of differing types, a collection is your only choice). From a speed standpoint, which approach you should choose depends on how you plan to access the objects. If you can associate a unique key with each object, then a collection is the fastest choice. Using a key to retrieve an object from a collection is faster than traversing an array sequentially. However, if you do not have keys and therefore will always have to traverse the objects, an array is the better choice. Arrays are faster to traverse sequentially than collections.
For small numbers of objects, arrays use less memory and can often be searched more quickly. The actual number where collections become more efficient than arrays is around 100 objects; however, this can vary depending on processor speed and available memory.
For More Information See "Using Collections as an Alternative to Arrays" in "More About Programming."