Wrox Home  
Search
Professional Refactoring in Visual Basic
by Danijel Arsenovski
April 2008, Paperback


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.

Note
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 Off and Option Strict Off but type declarations present)
  • Code written in statically and strongly typed style, but without compiler enforcement of strong typing (Option Explicit On and Option Strict Off but 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 Explicit and 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 Explicit and 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 Dim, Private, Public, or 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.

Related Refactoring

Use Set Option Explicit On refactoring to eliminate this smell.

Rationale

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 On help? 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 printersTeted is 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 On and 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)

Motivation

Explicit variable declaration can prevent number of typo-related bugs early on at compile time. It can improve code readability by stressing variable scope.

Related Smells

Use this refactoring to eliminate the Implicit Variable Declaration smell.

Mechanics

The 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 Dim, Private, Public, or ReDim.

Before

    Public Function BasketTotal()
        For Each item In Basket
            total += item.Price
        Next
        Return total
    End Function

After

    '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.