Excerpt from Professional Refactoring in Visual Basic
Learning VB Refactoring: Basic Programming Hygiene
by Danijel Arsenovski
In this article, you will begin to learn a preliminary VB refactoring, enforcing variable declaration. I call it preliminary because you can execute it even without deeper knowledge of the problem domain the code is meant to resolve. It is performed on the syntactic level and deals with problems that have their origin in VB backward compatibility or are related to good programming practices that I call "basic programming hygiene."
Almost all high-level programming languages implement the concept of types. By classifying values and expressions into types, you achieve a number of benefits: safety, optimization, abstraction, and modularity.
Most modern programming languages can be placed into one of two categories: statically typed or dynamically typed.
- In statically typed languages, type resolution is performed at compile time, and type information is provided explicitly in the code by the programmer himself in the form of a variable declaration.
- In dynamically typed languages, data types are not declared, and type information is not available until execution.
Visual Basic can be statically or dynamically typed. This behavior of VB's compiler is controlled by the
Option Explicit statement.
Languages are also differentiated by the level of type safety they provide. Strongly typed languages disallow operations on arguments that have a wrong type. Other type languages permit these operations by implicitly casting the types of arguments so that the operations in question can be performed, guided by rules that take both operands into account. The disallowing or allowing of implicit conversions in VB code is controlled by VB's
Option Strict statement.
In Visual Basic 2008 there is new and different type of Option statement. Option Infer lets you omit the As clause of your local variable declaration, but the code is still statically typed. In that sense it is more of a productivity feature than an additional type-system behavior. I deal with VB 2008 novelties in Chapter 15, "LINQ and Other VB 2008 Enhancements" of the book, Professional Refactoring in Visual Basic (Wrox, 2008, ISBN: 978-0-470-17979-6), and discuss Option Infer in that chapter.
Table 1 shows the kinds and levels of typing enforced in VB by the compiler when the
Option Explicit and
Option Strict options are active or inactive.
Table 1: VB's Option Statement in Relation to Typing Enforced by the Compiler
|Option Explicit On||Option Explicit Off|
|Option Strict On||Static strong||Dynamic strong (rare)|
|Option Strict Off||Static weak (problematic)||Dynamic weak|
This versatility of VB is unique and enables the effective use of VB for variety of purposes, from fast prototyping to industrial-strength applications. While .NET as a platform is mostly statically oriented (other languages like C# and managed C++ are statically typed), the flexibility of VB lets it fill the gap in the dynamically typed compartment.
However, in some cases, when programmers are not completely aware of the effect that
Option statements can have on the code, or when they are working with legacy code upgraded to VB .NET, they can produce potentially problematic code. Such code comes in two flavors:
- Code written in statically and strongly typed style, but without compiler enforcement of static or strong typing (
Option Explicit Offand
Option Strict Offbut type declarations present)
- Code written in statically and strongly typed style, but without compiler enforcement of strong typing (
Option Explicit Onand
Option Strict Offbut type conversions not present)
In this article you'll see a few details of the effects that
Option Strict and
Option Explicit statements have on your code.
Option Explicit and Option Strict, the .NET Effect
The effect that activating the VB compiler options
Option Strict and
Option Explicit has on the way you write your code is profound, but it is often overlooked. This is probably because of default settings — they let you program without having to take care of some type-conversion issues. The creators of VB have given you the ability to ignore a number of issues as you write code so that you can be productive fast, but such an approach can have some very negative sides to it. If you take a look at the official VB documentation, these issues are seldom discussed in detail. I will explain them and give you sufficient information so you are aware of the full impact of your decision to activate or deactivate these options.
When creating Visual Basic for the .NET platform, language makers had to take into an account a vast existing code base written in VB6 and previous versions of VB. It was certainly important to provide some upgrade path for existing legacy code. On the other hand, one of the most sought-after features of VB was strong static typing. Using strong static typing essentially means that you need to declare explicitly all your variables and their types and that you have to take care of all type conversions.
In order to accomplish both goals, some type of upgrade path and support for static typing, the following approach was adopted: VB .NET can work both with and without static typing, depending on a compiler option value:
- If you deactivate
Option Strict, you do not have to declare variable type, or declare variables at all. Also, all type conversions are performed automatically, without your having to write any code that will deal with type conversions. This is dynamic, weakly typed code.
- If you activate
Option Strict, you are obliged by the compiler to declare all your variables and their types, and all type conversions have to be performed deliberately and written down explicitly in code. This is static, strongly typed code. I will refer to such code as strict (
Option Strict On) or explicit (
Option Explicit On).
The problem is that you can still write your code in a strongly and statically typed style even without activating
Option Explicit and
Option Strict, but you don't get any tool support for it. If you forget to declare a variable or its type, or perform some potentially hazardous implicit conversion, the compiler does not complain. Instead, it tries to work things out to the best of its abilities. I will refer to such code — written in a statically and strongly typed style, but with compiler type checking deactivated — as relaxed or permissive.
On the other hand, once these options are activated, you can count on the compiler to perform all the necessary verifications and to compile the code only after all variables and types are declared and all type conversions performed explicitly. Needless to say, this is the preferred way to write code. If you are writing strongly and statically typed code, it only makes sense to count on the tool to provide you with compile-time type checking.
Setting Option Explicit On in Relaxed Code
The purpose of the
Option Explicit statement is to tell the compiler to enforce variable declaration. After this option is set, if any variable is encountered that has not been previously declared with a
ReDim statement, a compilation error will be reported, the code will not compile, and the offending identifier will be underlined in the VB editor.
Note that even if you do not place
Option Explicit On, you can still declare variables. The difference in this case is that you do not get the compiler to enforce the declaration of each and every variable.
Now I want to discuss why omitting to declare variables can be considered bad style, how you can convert code with omitted variables into explicit code, and how you can apply this method to the Rent-a-Wheels application.
Understanding the Set Option Explicit On Refactoring
At this point you might rightfully ask, "Why declare variables at all?" Because you have seen that you can write code without declaring variables, there must be some good reason to do so. Otherwise, you are only writing some redundant, unnecessary code.
A number of reasons exist for declaring variable type, but the most obvious one is that a number of bugs, a lot of times just simple typos, can be discovered at compile time. Imagine you have the following code snippet:
printers = GetPrinters() printersTested = 0 For Each printer In printers printer.PrintTestPage() printersTeted += 1 Next MsgBox(printersTested & " printers tested.", _ MsgBoxStyle.Information, "Printer test status")
Take a good look at this code. Do you see any problem with it?
It is fairly easy to understand what this code is doing. However, what is not so easy is to see that it contains a simple typing error that can cause you to spend a lot of time with a debugger in search of this very nasty type of insect.
Take look at this code again. This time, the offending line is shown in bold so you don't have to spend any more time in futile hunt for this evasive enemy of every bug-free, code-loving programmer.
printers = GetPrinters() printersTested = 0 For Each printer In printers printer.PrintTestPage() 'Offending line printersTeted += 1 Next MsgBox(printersTested & " printers tested.", _ MsgBoxStyle.Information, "Printer test status")
If you do not enforce explicit variable declaration, the compiler creates a new variable each time a corresponding new identifier is encountered in the code. With the sample I have just shown, a compiler has no way to guess that I actually meant to use the
printersTested variable and not to create a new
printersTeted variable. So it goes on quietly minding its own business and creates a new variable. And I end up with a very undesirable bug in my code.
Smell: Implicit Variable Declaration
Detecting the Smell
Use the compiler to detect variables that are declared implicitly. Place
Option Explicit On at the top of the file, compile the project, and look for a "Name someVariable is not declared" error in the Error window. The IDE will also underline the identifier in the Editor window if an undeclared variable is present.
Option Explicit On refactoring to eliminate this smell.
Failing to declare variables explicitly can lead to difficult-to-detect bugs resulting from simple typing mistakes. It can also lead to a convoluted use of variables. Code readability can benefit from explicit variable declaration.
So how does
Option Explicit Onhelp? Once you include the statement in your code, the offending line is underlined as an error in the editor, and in the error list an appropriate error description is displayed: "Name
printersTetedis not declared." Very clear, precise, and very helpful. You can then correct the error right away. Finally, this is how the snippet should look once I use
Option Explicit Onand correct the bug.
Option Explicit On '... Dim printers = GetPrinters() Dim printersTested = 0 For Each printer In printers printer.PrintTestPage() printersTested += 1 Next MsgBox(printersTested & " printers tested.", _ MsgBoxStyle.Information, "Printer test status")
Once you have declared all the variables, you should proceed by assigning the corresponding type to the variable.
Refactoring: Set Option Explicit On (Enforce Variable Declaration)
Explicit variable declaration can prevent number of typo-related bugs early on at compile time. It can improve code readability by stressing variable scope.
Use this refactoring to eliminate the Implicit Variable Declaration smell.
Option Explicit statement is module-level only.
Option statements have to be the first statements in the file. When transforming a project written in a relaxed variable-declaration style, start by placing the
Option Explicit On statement in a single file. (If you set this option on at the project level, you are bound to receive a significant number of error messages, and increased clutter might slow you down.) After you declare all the variables in one file and no errors are reported by the IDE, move to the next file. Complete this refactoring on the whole project before starting Set
Option Strict On refactoring.
After you have turned
Option Explicit on, the IDE will underline all undeclared variables and report errors ("Name VariableX is not declared") in the error list. Work to eliminate errors one by one by declaring undeclared variables using
Public Function BasketTotal() For Each item In Basket total += item.Price Next Return total End Function
'Option Explicit On statement added Option Explicit On '... Public Function BasketTotal() 'Variable declaration added Dim total Dim item For Each item In Basket total += item.Price Next Return total End Function
Enforcing Variable Declaration is just one of several useful preliminary refactorings. In Chapter 5, "Chameleon Language: From Weak Static Typing To Strong Dynamic Typing," of the book Professional Refactoring in Visual Basic, you'll also learn about Enforcing Variable Type Declaration and Explicit Type Conversions as well as multiple examples for applying these refactorings.
This article is excerpted from Chapter 5," Chameleon Language: From Weak Static Typing to Strong Dynamic Typing," of the book, Professional Refactoring in Visual Basic (Wrox, 2008, ISBN: 978-0-470-17979-6), by Danijel Arsenovski. Daniel is a software developer from Santiago, Chile. Currently, he works as Product and Solutions Architect at Excelsys S.A, designing Internet banking solutions for numerous clients in the region. He started experimenting with refactoring while overhauling a huge banking system, and he hasn't lost interest in refactoring ever since. He pioneered the use of refactoring as a vehicle for a VB 6 code upgrade to VB .NET. Arsenovski is a contributing author for Visual Studio Magazine and Visual Systems Journal, holds a Microsoft Certified Solution Developer (MCSD) certification, and was named Visual Basic MVP in 2005. You can take a look at his blog at http://blog.vbrefactoring.com.