This is the second in a series on setting compiler options for Visual Studio VB.NET projects, versions 2005-2010. You can access the first piece here. Compiler options are project-level settings that determine how the compiler behaves when it compiles your code. You view and set compiler options in the Compile tab of the project properties sheet, as shown in Figure A. In this second part, I will discuss Option Strict.
What it means
Option Strict is a single switch, On or Off. It determines whether VB.NET requires type declarations and puts certain restrictions on implicit conversions. In Visual Studio 2005 and 2008, it’s pretty straightforward; with 2010, it gets a little more complicated. Here’s a summary of how the compiler behaves when Option Strict is set to On:
- Requires type declarations for all variables, constants, routine parameters, and function return values, regardless of scope, unless: In 2010, Option Infer is set to On, in which case type declarations are required only for routine parameters, function return values, and variables outside of local scope.
- Disallows late binding.
- In 2010, disallows implicit conversions to Object.
We’ll discuss Option Infer lightly here to keep things clear, but will go into more detail on it in Part 3.
In VB, a type declaration is simply an As clause, whereby you specify the data type. Visual Basic is a weakly-typed language, so unless you tell VS otherwise, it will let you code merrily along without declaring types, as I’ve done here:
Dim MysteryVariable = 22205-7509
What kind of data does my mystery variable contain? Is it a number, a string, or something else? It’s not clear, and by setting Option Strict to Off, you’re saying that it doesn’t matter. If the compiler decides that it’s a number, it’s fine with me. And if it decides that it’s a string, that’s fine with me too. And decide it will-it will make its best guess, and store it that way. This is called implicit typing, or a type inference; the compiler infers from the data what the type is. This is how VB.NET behaves with Option Strict set to Off.
Setting Option Strict to On forces you to declare variable types before using them, like so:
Dim PostalCode As String = "22205-7509"
Now the compiler is not allowed to decide what it is. I’ve told it. It’s a String.
As mentioned above, VS 2010 lets you relax this restriction substantially by turning on Option Infer. Option Strict = On in VS 2005 and 2008 is exactly equivalent to Option Strict = On + Option Infer = Off in 2010. With Option Infer = On, the compiler behaves as if Option Strict = Off for all variables and constants within routines. In 2012, with Option Infer set to Off, “Dim MysteryVariable = 22205-7509″ is perfectly legal within any routine.
Another way of describing this restriction (and the way it is explained in MSDN) is to say that it restricts conversions to widening conversions. This simply means that the compiler will let you stick a small variable into a big variable, but not the other way around, for hopefully obvious reasons. The following (widening conversion) is allowed:
Dim SmallNumber As Integer = 1 Dim BigNumber As Long = 2 BigNumber = SmallNumber
The following (narrowing conversion) is not:
Dim SmallNumber As Integer = 1 Dim BigNumber As Long = 2 SmallNumber = BigNumber
Without this restriction, every variable starts out as an Object, making potentially every assignment into a narrowing conversion, where data loss can easily occur.
This restriction corresponds to the warning configuration named, “Implicit conversion” (see Figure A). When Option Strict is set to On, “Implicit conversion” is set to Error.
Late binding refers to the use of a property or method of a variable whose type is Object. In other words, it’s when you assume you know what the variable is when you really can’t guarantee being right. Here is an example of a late-bound call (on MysteryVariable):
Dim MysteryVariable As Object = "22205-7509" Dim MysteryVariableLength As Integer MysteryVariableLength = MysteryVariable.Length
MysteryVariable is an Object, which means that it doesn’t contain the data “22205-7509″, it merely holds a pointer to the data. Thus, the data’s type (string, integer, or whatever) is unknown at compile time. There is therefore no way for the compiler to know whether MysteryVariable will even have a Length property. So, when Option Strict is set to On, the compiler will not let you code it that way. It wants to know whether MysteryVariable has such a property before it will let you write that line. Option Strict = On means no late binding is allowed.
This restriction corresponds to the warning configuration named “Late binding; call could fail at runtime” (see Figure A). When Option Strict is set to On, “Late binding; call could fail at runtime” is set to Error.
Implicit conversions to Object
An implicit conversion to Object occurs whenever the compiler can’t tell whether a variable is anything but an Object. This restriction (as part of Option Strict) only applies to VS 2010, but mainly to deal with things when Option Infer is Off, since that’s when you can have variables without a type declaration being implicitly converted to Object.
This restriction corresponds to the warning configuration named “Implicit type; object assumed.” When Option Strict is set to On, “Implicit type; object assumed” is set to Error.
One final point: Option Strict = On implies variable declarations, so if Option Strict is On, so is Option Explicit.
Why it’s important
The chief hazard of skipping type declaration is unpredictable behavior. When variables have no explicit type, the runtime has to infer their type, which means that their type will be determined by the values they contain. With values like “22205-7509″, it’s going to have to make a compiler’s version of an educated guess. It could represent a postal code or an equation, or maybe even a range, but in any case, you have no way of knowing ahead of time how the compiler will rule on this. It’s going to make up its mind when it gets the data. And if it decides that the value is a string, it will cast the value as such and return “22205-7509″. If it decides that it’s an equation, it will subtract 7,509 from 22,205 and return 14,696. It’s hard to imagine a program that would want unpredictability like that-unless the whole point of the program were to output unpredictable results!
Problems like this can easily hide behind little subtleties. In the following two lines, the compiler will cast the first as a string and the second as an integer, all depending on whether you use quotation marks:
Dim PostalCode1 = "22205-7509" � '<-- System.Int32 Dim PostalCode2 = 22205-7509 '<-- System.String
But that’s a contrived example, because I’ve specified the value inline. If the value is passed in as input, who knows how it will look to the compiler? Here’s another contrived example:
Private Function GetFormattedPostalCode(ByVal InputValue) Dim ReturnValue = InputValue '<-- System.? Return ReturnValue '<-- System.? End Function
Another big hazard of skipping type declaration is the loss of type safety. If you declare a variable that should be an integer but don’t declare it as such, the runtime will not complain if it gets a string or a byte array instead. Then later on, when your program uses that variable, your assumption will have been wrong. That means you can get runtime errors at seemingly random times in seemingly random places, all depending on the data they get.
One final hazard is lost performance. Implicit typing creates runtime overhead that can easily be optimized out of the program by explicit data types. To be clear, the overhead will not be noticeable in small programs and in programs that don’t move much data around. But as with all things small, the overhead adds up quickly, and in larger programs and in multiuser programs, such as web sites, it can add up very quickly. And even if you’re OK with the overhead, there’s no benefit to it-it just makes your program slower.
What to do with it
I’ve read that Microsoft decided to default Option Strict to Off in VB.NET projects to help developers migrate projects from earlier versions of VB. If true, there’s really no reason to leave the default alone unless that’s what you’re doing. Predictable behavior, type safety, and good performance are good things to get out of your software, and that requires Option Strict = On.
As with Option Explicit, if you leave it turned off, you will give up compile-time protections without getting anything in return. And even if you are migrating a VB6 project to .NET, I’d argue that you’re better off setting Option Strict to On and fixing all the ambiguities that the compiler catches.
So, change the option in your project and declare all your types. If it’s not clear what a type should be, you’ve got a readability problem as well as a compiler error; fix both. Rename the variables, parameters, or return values so it’s clear what they’re doing. Their names should say what they represent; fix the names as well as choosing types.
If the project does compile, go through every line of code anyway and make sure the types make sense. Then test it thoroughly.
Finally, change the IDE’s default, so that all new projects start out with strict typing; set your IDE to use Option Strict On for all new projects. Go into Tools, Options, Projects and Solutions, VB Defaults, and change the default to On (Figure B). (If you are running Visual Studio 2010, you will also see an Option Infer setting.)
Exceptions and variations
What if your program needs ambiguous data types? There are situations in which the programmer cannot know what type of data the variable will hold in advance. For example, your variable may hold the user’s answer to a question, and the answer could be anything the user can type or paste in, including an image. In cases like that, it’s better explicitly to use a variable of a known type that can handle the ambiguity, such as an Object, than to let the runtime decide its type for you. Leave Option Strict On, and declare your variable as something that you can work with. But make it as precise as possible.
One situation that may confound your efforts to set Option Strict to On is the large project that you inherit on a tight deadline. More than once I’ve inherited projects that were littered with undeclared variable types, and I simply didn’t have time to fix them all and test the changes adequately. In that case, you can leave it Off in the project but turn it On in individual modules. Just place the line at the top of the module itself, before any class declarations:
Option Strict On Public Class MainForm End Class
That’ll give you time to implement your fixes in manageable chunks.
Option Strict is a compiler option in VB.NET with a problematic default, and unless you change it, you’re giving up some free and powerful defenses against easy-to-miss bugs. Don’t let the madness continue. Set Option Strict to On in all your VB.NET projects.