What’s New in Visual Basic 9.0? Part 1

ith the release of Visual Studio 2008, Microsoft has also updated the VB language to its latest version, 9.0. In VB 9.0, there are several key language enhancements that have been made to support the new Language Integrated Query (LINQ) feature announced earlier by Microsoft. This article will walk you through each of these new language enhancements and provide a couple of code examples to illustrate their uses.

Nullable Type
As you are no doubt aware, all un-initialized value types in VB have a default value when they are declared. For example, the following declaration declares a Boolean variable:

        Dim married As Boolean

Because it has not been initialized, married now contains the default value of False. However, there are times where you do not know the marital status of a person and hence the variable should neither be True nor False. In VB 9.0, you can now declare value types to be nullable, i.e., they do not yet have a value.

To make the married variable nullable, the above declaration can be rewritten in three different ways (all are equivalent):

        Dim married As Boolean?        Dim married? As Boolean        Dim married As Nullable(Of Boolean)

In this case, married can take one of the three values: True, False, or Nothing. The following code snippet will print out “Not Married”:

        If married Then            MsgBox("Married")        Else            MsgBox("Not Married") '---this will be printed---        End If

This is because the If statement evaluates to a False (married is currently Nothing) and hence the Else block will execute. A much better way to check would be to use the following snippet:

        If married Then            MsgBox("Married")        ElseIf Not married Then            MsgBox("Not Married")        Else            MsgBox("Not sure") '---this will be printed---        End If

Once a nullable type variable is set to a value, you can set it back to nothing by using Nothing, as the following example shows:

        married = True    '---set it to True---        married = Nothing '---reset it back to nothing---

To check the value of a nullable variable, use the HasValue property, like this:

        If married.HasValue Then            '---this line will be executed only             'if married is either True or False---            MsgBox(married.Value)        End If

Do not use the “=” operator to test against Nothing, as this will always evaluate to Nothing, like the following example shows:

        If married = Nothing Then            '---this line will NEVER be executed---            MsgBox(married.Value)        End If

Instead, you should use either the Is or IsNot operator:

        If married IsNot Nothing Then            '---this line will be executed only             'if married is either True or False---            MsgBox(married.Value)        End If
Figure 1. Default: All unspecified types default to Object.

Type Inference
In VB 8.0, you could declare a variable without specifying its type. In such cases, the variable is of type Object, which means and you needed to perform typecasting during runtime. The downside to this is that IntelliSense wouldn’t know the variable type during design time, making it difficult for you to deal with the type (see Figure 1).

VB 9.0 offers a new option: Option Infer. This option is turned on by default. Thus, all variables declared without specifying the type are automatically be inferred by its initializer. Consider the following example:

        Dim obj        obj = 5       '---obj is Now integer---        obj = "Hello" '---obj is now string---        Dim num = 9   '---obj is integer---        num = "World" '---error---

Here, obj is of type Object because there is no initializer. Hence, during runtime it can take on values of any type. In contrast, num is automatically inferred as type Integer because of the initializer value of num will cause a runtime error. Unfortunately, unless you use the Option Strict On, this error will not be flagged during compile time.

Figure 2. Inferred: Loop variants are also typed inferred.
Figure 3. Inferred: The loop variant’s type is inferred by the content of the pts array.

Automatic type inferencing also applies to loop variants. Figure 2 shows that, depending on the values assigned to the loop variable i, its type will be automatically inferred.

As another example, consider the code shown in Figure 3. Here, pts is an array of Point objects. The loop variant pt will automatically be inferred to be of type Point, as evident in IntelliSense.

In contrast, if pts contains a mixture of Point and Size objects (see Figure 4), then the pt loop variant will then be inferred to be of type Object.

Figure 4. Inferred: pt is now inferred to be of type Object.

The If Operator
VB 9.0 also allows you to use the if operator to evaluate an expression and conditionally return one of two values. Consider the following example:

        Dim num = 20        MsgBox(If(num > 0, "Positive", "Negative"))

In the above statement, if num is greater than 0, the string “Positive” would be displayed, else “Negative” would be displayed. The if operator first evaluates the first argument, which is num>0, and if the result of that expression is true, the second argument would be evaluated and returned. If the result is false, the third argument is evaluated and returned.

The if operator is similar to the IIf() function, with one notable difference: the If operator uses short-circuit evaluation?that is, it only evaluates one of the arguments depending on the result of the first expression. The following example makes this clear:

        Dim d = 0        '---prints out 0---        MsgBox(If(d <> 0, 50  d, 0))        '---this one will result in an runtime error---        MsgBox(IIf(d <> 0, 50  d, 0))

Here, because d is 0, if you use the if operator, only the third argument is evaluated. If you use the Iif() function, both the second and third arguments would be evaluated regardless, resulting in a division by zero error for the second argument (50 d).

You can also use the If operator with two arguments. Consider the following example:

        Dim conn As SqlConnection = Nothing        conn = If(conn, New SqlConnection("Data Source=.SQLEXPRESS; " & _               "Initial Catalog=pubs;Integrated Security=True"))        '---prints out the pubs connection string---        MsgBox(conn.ConnectionString)

Here, if conn (the first argument) evaluates to Nothing, the second argument is returned (which is a SqlConnection object). If conn evaluates to anything other than Nothing, then the first argument (which is conn in this case) is returned. Contrast the above statements with the approach that you’d normally take:

        If conn Is Nothing Then            conn = New SqlConnection( _            "Data Source=.SQLEXPRESS;Initial Catalog=pubs; " & _            "Integrated Security=True")        End If        MsgBox(conn.ConnectionString)

Using the if operator with two arguments makes your code cleaner and easier to read.

In the following example, the Northwind connection string will be printed out instead:

        Dim conn As SqlConnection         conn = New SqlConnection("Data Source=.SQLEXPRESS; " & _           "Initial Catalog=Northwind;Integrated Security=True")        conn = If(conn, New SqlConnection( _           "Data Source=.SQLEXPRESS;Initial Catalog=pubs; " & _           "Integrated Security=True"))        '---prints out the Northwind connection string---        MsgBox(conn.ConnectionString)

Object Initializers
In VB 8.0, after instantiating an object, you would normally initialize the various properties of the object explicitly, like this:

        Dim ptB = New Point        With ptB            .X = 5            .Y = 3        End With

But in VB 9.0, you can initialize an object at the same time it is instantiated. You accomplish this using object initializers. With them, the above statements can be rewritten like this:

        Dim ptB = New Point With {.X = 5, .Y = 3}

The “.” indicates the property that you are initializing. If the class has constructor(s), you can also combine the constructor with the object initializer. For example, the Size class contains two overloaded constructors, one of which takes in a Point object. The following code shows you how to instantiate a Size class using a constructor, as well as the object initializers:

   Dim s As New Size(New Point(4, 5)) With {.Height = 30, .Width = 40}

You can also use the object initializers with arrays:

        Dim pts() As Point = _           {New Point With {.X = 1, .Y = 2}, _            New Point With {.X = 3, .Y = 4}, _            New Point With {.X = 5, .Y = 6}}

Anonymous Types
Another new feature in VB 9.0 is the anonymous type. Anonymous type allows you to define a new type without having to define a class. Consider the following example:

        Dim contact1 = New With { _           .id = "54321", _           .Name = "Wei-Meng Lee", _           .email = "[email protected]" _        }

Here, the Contact1 object has three properties?email, all of which are initialized during the instantiation stage. Moreover, you can change the values of these properties:

        contact1.Name = "Lee, Wei-Meng"        contact1.email = "[email protected]"

However, there are times that you want to make certain properties read-only. To do so, use the Key keyword. The following shows three more objects created using anonymous types, but this time their id and email properties are read-only:

        Dim contact2 = New With { _           Key .ID = "12345", _           .Name = "Richard Wells", _           Key .email = "[email protected]" _        }        Dim contact3 = New With { _           Key .ID = "12345", _           .Name = "Wells, Richard", _           Key .email = "[email protected]" _        }        Dim contact4 = New With { _           Key .ID = "54321", _           .Name = "Wells, Richard", _           Key .email = "[email protected]" _        }

To compare the equality of two anonymous types, use the Equals() method. Two anonymous types are considered equal only if the values of their key properties (read-only) are the same, as the following example illustrates:

        MsgBox(contact1.Equals(contact2)) '---returns False---        MsgBox(contact1.Equals(contact1)) '---returns True---        MsgBox(contact2.Equals(contact3)) '---returns True---        MsgBox(contact3.Equals(contact4)) '---returns False---

Extension Methods
In the past, to add additional methods to a class, you had to subclass it and then add the methods to the subclass. In VB 9.0, you can just use the new extension methods feature to add a new method to an existing CLR type.

To see how extension methods work, consider the following example: suppose you deal very frequently with the Point class and you want to be able to quickly find out the distance between two points. In this case, you might be better served if you added a new function called DistanceFromThisPointTo() to the Point class, allowing all instances of the Point class to make use of this method. To do so, define a new module (you need to import the System.Runtime.CompilerServices namespace) and define the extension method (a function) within it, like this:

Imports System.Runtime.CompilerServicesModule Module1     _    Public Function DistanceFromThisPointTo( _       ByVal PointA As Point, ByVal PointB As Point) As Single        Return Math.Sqrt( _           (PointA.X - PointB.X) ^ 2 + _           (PointA.Y - PointB.Y) ^ 2)    End FunctionEnd Module

Here, you add the attribute to the extension method (DistanceFromThisPointTo()) and the first parameter of the extension method (which is of type Point) indicates to the compiler that this extension method must be added to the Point class. The rest of the parameter list is then the signature of the extension method. To use the extension method, simply call it from a Point object, like this:

        Dim ptA As New Point(3, 4)        Dim ptB As New Point(5, 6)        MsgBox(ptA.DistanceFromThisPointTo(ptB))

Extension methods can be applied to the following types:

  • Classes (reference types)
  • Structures (value types)
  • Interfaces
  • Delegates
  • ByRef and ByVal arguments
  • Generic method parameters
  • Arrays

Partial Methods
In VB 8.0, you had the concept of partial classes, in which the definition of a class could be split into more than one class definition. In VB 9.0, this concept is extended to methods?partial methods. To see how partial methods work, consider the following example: suppose you have a partial Contact class that contains two properties: Name and Email (see Listing 1).

Now, further suppose you want to allow the users of this partial class to optionally log the email address of each contact when its Email property is set. In this case, you can define a partial method called LogEmail(), as shown in Listing 2.

In this example, you’ve defined a partial method named LogEmail() that is called when a contact’s email is set via the Email property. Observe that this method has no implementation. So where is the implementation of the LogEmail() partial method? It can optionally be implemented in another partial class. For example, if another developer decides to use the Contact partial class, s/he can define another partial class containing the implementation for the LogEmail() method:

Partial Public Class Contact    Private Sub LogEmail()        Console.WriteLine(_email)    End SubEnd Class

So now, when you instantiate an instance of the Contact class, you can set its Email property as follows and a line will be printed in the output window:

        Dim Contact1 As New Contact        Contact1.Email = "[email protected]" 

What if there is no implementation of the LogEmail() method? In that case, the compiler simply removes the call to this method and there’s no change to your code.

Partial methods are useful when you’re dealing with generated code. For example, suppose the Contact class is generated by a code generator. The signature of the partial method is defined in the class, but the implementation is totally up to you to decide if you need to use it.

When defining partial methods, note the following conditions:

  • The method must be a Sub, not a Function
  • The body of the method must be left empty
  • The access modifier must be Private

Lambda Expressions
In VB 9.0, a Lambda expression is a nameless function that evaluates a single expression and returns its value. Consider the following function:

    Private Function CubeRoot(ByVal num As Single) As Double        Return Math.Pow(num, 1 / 3)    End Function

Before, you’d call the CubeRoot() function using this argument:

        MsgBox(CubeRoot(8)) '---returns 2---

Using a Lambda expression, you can rewrite and call the CubeRoot() function as follows:

        Dim CubeRoot = Function(num As Single) Math.Pow(num, 1 / 3)        MsgBox(CubeRoot(8)) '---returns 2---

A Lambda expression is defined using the Function keyword, followed by its parameter and then the single expression within the function. Note that it is optional to specify the parameter type and there is no need to specify the return type. The above Lambda expression can be rewritten as:

        Dim CubeRoot = Function(num) Math.Pow(num, 1 / 3)

The above Lambda expression uses type inferencing to determine the Lambda expression. You can also explicitly define a Lambda expression using the Func keyword, like this:

        Dim CubeRoot As Func(Of Single, Double) = _           Function(num As Single) Math.Pow(num, 1 / 3)

Here, you use the Of keyword to specify the type of parameter(s) and their return type. The rightmost parameter always specifies the return type; in this case, the return type is Double. The parameters on the left then specify the input parameters. In this case, there is only one input parameter of type Single.

The following Lambda expression has no input parameters and returns a Boolean value:

Dim ReturnTrue As Func(Of Boolean) = Function() True

The following Lambda expression has two input parameters of type Integer and returns a Double value:

Dim Multiply As Func(Of Integer, Integer, Double) = Function(a, b) a * b

A Lambda expression can also return another Lambda expression. Consider the following expression:

        Dim AddConstant = Function(constant) Function(y) constant + y

To better understand the above Lambda expression, rewrite it as follows:

        Dim AddConstant = Function(constant) _                             Function(y) constant + y

As you can see, the AddConstant expression takes in a single argument and returns another Lambda expression, which is:

                             Function(y) constant + y

To use the AddConstant expression, you can call it using the following:

        Dim z = AddConstant(4)        MsgBox(z(7)) '---prints out 11---

Here, z is another function that you can call with a single argument. By calling the AddConstant function with the argument 4, z is essentially:

                             Function(y) 4 + y

Therefore, whatever value you pass into z will be added to the value 4, which in this case the return value is 11.

Lambda expressions are useful in cases where you need to pass in a function for a parameter whose type is delegate. For example, suppose you have an array of controls:

        Dim allControls As Control() = _           {Button1, CheckBox1, Button2, CheckBox2}

To retrieve all the CheckBox controls within this array, you can use one of the many extension methods available for the array (see Figure 5).

Figure 5. Methods: The List of extension methods for an array.
Figure 6. View the Connection Details: After specifying the database properties, you should see the data connection details.

The Where() extension method takes in a Lambda expression that allows you to test each element of the array for a specific condition (see Figure 6).

You can use the following Lambda expression to retrieve all the CheckBox controls in the array:

    Dim checkBoxes = allControls.Where(Function(c) TypeOf c Is CheckBox)

More to Come!
This is only a partial list of the new features in VB 9.0. Be sure to download the trial edition of Visual Studio 2008 (or download the various free Expression editions) if you have yet to experience the power of all these language extensions. And stay tuned for Part 2 to delve into the opportunities provided by VB 9.0’s LINQ support.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin


Recent Articles: