Introduction

We are proud to release Visual Basic 10, the latest version of the Visual Basic language. This is the version of the language that ships with Visual Studio 2010 and .NET 4.

Microsoft has committed to a policy of “co-evolution” between Visual Basic and C#, where major new features will appear in both languages at the same time, and important new features that appear in both languages in this release include interop with the Dynamic Language Runtime, and the ability to build solutions that no longer require Primary Interop Assemblies to be deployed on end-user machines.

Some new features in this version of the language, such as implicit line continuations, provide a cleaner or simpler syntax that will be used in almost every function you write. Other new features, such as statement lambdas, enable powerful idioms in new Microsoft frameworks such as Silverlight 4 and the Task Parallel Library.

Visual Basic 10 also marks the first release in which the language specification is deployed with the product. It can be found in C:\Program Files (x86)\Microsoft Visual Studio 10.0\VB\Specifications.

Visual Basic has always strived to be the most productive tool for building line-of-business, data-centric applications.  Version 9.0 of the language delivered Language Integrated Query (LINQ), first-class XML support, as well as other core features such as nullable types. We are proud to release Visual Basic 10, which makes the language cleaner and simpler and more powerful.

New Language Features

Multi-Line Statement Lambdas

A statement lambda is a lambda expression that represents a function containing one or more statements. 

Dim nums() As Integer = {1, 2, 3, 4, 5}

    nums = Array.FindAll(nums, Function(n)

                                   Console.WriteLine("testing " & n)
                                   Return n > 2

                               End Function)

Just like regular lambdas, the compiler will infer the type of each parameter where possible (in this case inferring n as Integer).  The compiler will also infer the lambda’s return type by using the dominant type algorithm (see section 8.13 of the Language Specification, usually at “C:\Program Files (x86)\Microsoft Visual Studio 10.0\VB\Specifications”) to choose between the types of each expression in a Return statement.  For example:

'numDelegate is an anonymous delegate compatible with Func(Of Integer,  
     Double)
    Dim numDelegate = Function(n As Integer)

                          If n Mod 2 = 0 Then
                              Return 3
                          Else
                              Return 3.14
                          End If

                      End Function

In this case, the compiler sees that the return type could be Integer or Double, and so it picks Double as it is a wider type that can encompass any Integer. 

Alternatively, you can explicitly specify the return type you want by using an As clause.  In this case, the compiler will just use “Single” and will not attempt to infer a return type:

Dim lambda = Function(n As Integer) As Single
                     If n Mod 2 = 0 Then
                         Return 3
                     Else
                         Return 3.14
                     End If
                 End Function

Sub Lambdas

Just as the “Function” keyword can be used to create a multiline lambda that returns a value, the “Sub” keyword can be used to create a multiline lambda that does not return a value:

Array.ForEach(nums, Sub(n)
                            Console.Write("Number: ")
                            Console.WriteLine(n)
                        End Sub)

Single-line Sub Lambdas

Visual Basic 9.0 only supported lambdas that were a single expression that returned a value; for example, the following line was an error:

'Error - Console.WriteLine doesn't return a value
    Array.ForEach(nums, Function(n) Console.WriteLine(n))

With Visual Basic 10, lambdas can now contain a single statement:

'Valid
 Array.ForEach(nums, Sub(n) Console.WriteLine(n)) 'Valid

Uses of statement lambdas

One important use of multiline lambdas is in Silverlight applications for asynchronous operations. For instance,

Dim client As New WebClient
    AddHandler client.DownloadStringCompleted,
        Sub(sender As Object, e As DownloadStringCompletedEventArgs)
            If Not e.Error Is Nothing Then Return
            MessageBox.Show(e.Result)
        End Sub

client.DownloadStringAsync(New Uri("http://blogs.msdn.com/lucian"))

Note: to create Silverlight projects you have to download the Silverlight 4 SDK. Also, read on that site why Silverlight’s protection against cross-site scripting attacks will cause it to throw a SecurityException, and how to use a file “clientaccesspolicy.xml” to make it work.

Another important use of statement lambdas is in the new Task Parallel Library. For instance,

Dim nums() As Integer = {1, 2, 3, 4, 5}
 nums.AsParallel.ForAll(Sub(n) Console.WriteLine(n))

Implicit Line Continuation

The underscore character is used in Visual Basic to indicate that the current logical line is being split up over one or more physical lines.  Visual Basic 10 removes the requirement for an underscore to be present after certain tokens where its presence can be inferred (i.e. the line continuation character becomes “implicit”).  While the need to use underscore has not been entirely removed from the language, the intention is that developers will not have to use it in the vast majority of lines they write.

At a high level, the line continuation character is implicit in the following situations:

  1. After an attribute
  2. After a comma
  3. After a dot (i.e. for method invocation)
  4. After a binary operator
  5. After a LINQ query clause
  6. After a (, {, or <%=
  7. Before a ), }, or %>

The following code demonstrates some of the places where implicit line continuation can be used:

<Attribute()>
    Function Go(
                    ByVal x As Integer,
                    ByVal y As Integer,
                    ByVal z As Integer
                )
        Dim query =
            From n In {
                       123,
                       456,
                       789
                      }
            Order By n
            Select n +
                   x

    End Function

The following tokens carry an implicit line continuation:

Token Before After
,   X
(   X
) X  
{   X
} X  
<%=   X
%> X  
< (in an attribute)   X
> (in an attribute) X  
Aggregate X X
Distinct X X
From (in a query) X X
From (in a collection initializer)   X
Group By X X
Group Join X X
Join X X
Let X X
Order by X X
Select (in query context) X X
Skip X X
Skip While X X
Take X X
Take While X X
Where X X
In X X
Into X X
On X X
Ascending X X
Descending X X
^ Operator    X
* Operator   X
/ Operator   X
\ Operator   X
Mod Operator   X
+ Operator (unary and binary)   X
^= Operator   X
*= Operator   X
/= Operator   X
\= Operator   X
+= Operator   X
-=Operator   X
<<= Operator   X
>>= Operator   X
&= Operator   X
< Operator    X
<= Operator   X
> Operator   X
>= Operator   X
= Operator   X
<> Operator   X
Is Operator   X
IsNot Operator   X
Like Operator   X
& Operator  
And Operator    X
Or Operator   X
Xor Operator   X
AndAlso Operator   X
OrElse Operator   X
<< Operator    X
>> Operator   X

Auto-implemented Properties

Developers often need to create simple entity classes or containers for data, in which the properties defined follow a very simple structure:

Private _FirstName As String

Property FirstName() As String
            Get
                Return _FirstName
            End Get
            Set(ByVal value As String)
                _FirstName = value
            End Set
 End Property

Auto-implemented properties provide a simple one-line way of expressing this concept:

Property ID() As Integer
Property FirstName() As String
Property LastName() As String

In this case the compiler will generate a backing field with the same name as the property, but with a preceding underscore.  It will also fill in the property’s getter and setter.

Initializers can be used to give an auto-implemented property a default value (which gets set in the class’ constructor):

Property ID() As Integer = -1
    Property SupplierList() As New List(Of Supplier)
    Property OrderList() As New List(Of Order) With {.Capacity = 100}
    
    <DefaultValue("-")> 
Property Name() As String Implements ICustomer.Name

Auto-implemented properties cannot have parameters, nor can they be declared ReadOnly or WriteOnly.

Collection Initializers

Collection initializers provide a way to initialize a collection type and provide it with a series of default values within a single expression.  For example:

Dim list = New List(Of String) From {"abc", "def", "ghi"}

Each element after the “From” keyword will be passed to the Add method on the type:

list.Add("abc")
list.Add("def")
list.Add("ghi")

Similarly, Dictionaries can also be initialized this way:

Dim list As New Dictionary(Of Integer, String) From
                                                        {{1, "abc"},
                                                         {2, "def"}}

When the elements after “From” are nested, the compiler will “unpack” the elements inside each set of brace and pass them sequentially to a single Add call:

list.Add(1, "abc")
list.Add(2, "def")

Developers are free to provide their own implementation of Add, either as an instance method on the type or through an extension method:

Dim list As New List(Of Customer) From {
                                            {123, "Jonathan", "Aneja"},
                                            {456, "Lucian", "Wischik"},
                                            {789, "Paul", "Vick"}
                                           }

    Class Customer
        Property ID As Integer
        Property FirstName As String
        Property LastName As String
    End Class

    <Extension()>
    Sub Add(list As List(Of Customer),
            ID As Integer,
            FirstName As String,
            LastName As String)

        list.Add(New Customer With {
                                        .ID=ID,
                                        .FirstName=FirstName,
                                        .LastName=LastName
                                   }
    End Sub

Array Literals

Array literals provide a compact syntax for declaring an array whose type is inferred by the compiler.

Dim a = {1, 2, 3} 'infers Integer()
Dim b = {1, 2, 3.5} 'infers Double()
Dim c = {"1", "2", "3"} 'infers String()
Dim d = {1, "123"} 'infers Object() (warning with Option Strict On)

Nested array literals can be used to produce multidimensional arrays:

Dim e = {{1, 2, 3}, {4, 5, 6}} 'infers Integer(,)
Dim f = {({1, 2, 3}), ({4, 5, 6})} 'infers Integer()() (jagged array)

An array literal always takes its type from the context, if applicable:

Dim g As = IEnumerable(Of Object) = {1, 2, 3} ' uses Object()
GetType(String).GetConstructor({}).Invoke({}) ' uses Type() then Object()
    
Sub test(ByVal x As Double())
 End Sub

test({1, 2, 3}) ' uses Double()

Only when the context doesn’t say which type to use, will the type of the array be inferred from its elements.

Optional Parameters Default To Nothing

Optional parameters can now be of any type, including Nullables and Value types:

Sub Add(x As Integer, y As Integer, Optional z As Integer? = Nothing)

Sub Add(x As Integer, y As Integer, Optional z As Double? = 4)

Sub Test(x As IntPtr  = Nothing)

An optional parameter can be initialized either with a constant (if the type of the parameter is compatible with that constant), or with the “Nothing”. Note that “Nothing” is the only expression that can be used to initialize a user-defined class or structure.

Generic Co- and Contra-variance

The following code is now legal in Visual Basic 10:

Dim strings As IEnumerable(Of String) = New List(Of String)
Dim objects As IEnumerable(Of Object) = strings

Intuitively it makes sense, on the grounds that “if someone asks to enumerate through a collection of objects, and I give them my collection of strings,  it should be fine since String inherits from Object.” This is called covariance.

Similarly, the following code is now legal in Visual Basic 10:

Dim f As Action(Of Object) = Function(o As Object) Console.WriteLine(o)
Dim g As Action(Of String) = f

The intuition here is that “if this action has the power to print out any object, and someone asks just for an action which has the power to print any string, it should be fine since String inherits from Object”.  This is called contravariance.

What has changed to allow these examples is that some key interfaces and delegates in the .Net framework are now declared with the “Out” and “In” keywords:

Interface IEnumerable(Of Out T)
Delegate Sub Action(Of In T)

The “Out” keyword here means that IEnumerable(Of Type1) can be widened to IEnumerable(Of Type2) so long as Type1 has a widening reference conversion to Type2. For instance, String has a widening reference conversion to Object, and ArgumentException has a widening reference conversion to Exception.

Note that this conversion from IEnumerable(Of Type1) to IEnumerable(Of Type2) is efficient: it is basically free at runtime. This is different from the old way of doing the conversion, e.g. “strings.Cast(Of Object)()”, which involved the runtime cost of iterating through every element in the collection and casting it.

The “In” keyword works in reverse. Here it means that Action(Of Type1) can be widened to Action(Of Type2) so long as Type2 has a widening reference conversion to Type1.

The keywords “Out” and “In” are only allowed in interface and delegate declarations. Here is an example which combines both:

Interface ITest(Of Out TO, In TI)
        Function a() As TO
        Sub b(ByVal x As TI)

        ReadOnly Property c() As TO
        WriteOnly Property d() As TI

        Sub e(ByVal x As Action(Of TO))
End Interface

For reasons of type safety, the “Out” generic type parameters may only ever be used in output positions, e.g. as the return type of a function or as the type of a readonly property. And the “In” generic type parameters may only ever be used in input positions, e.g. as the type of an argument or the type of a writeonly property.

It is subtle, the exact definition of what makes an input or output position - as illustrated by “Sub e” above! The best way to understand the feature is to experiment hands-on with the language, or read section 4.9.3 of the Visual Basic Language Specification (installed at C:\Program Files (x86)\Microsoft Visual Studio 10.0\VB\Specifications).

Limitations

Variant type parameters can only be declared on interfaces and delegate types, due to a restriction in the CLR.  Variance only applies when there is a reference conversion between the type arguments.  For instance, an IEnumerable(Of Integer) is not an IEnumerable(Of Object), because the conversion from Integer to Object is a boxing conversion, not a reference conversion.

When writing your own frameworks and classes, our guidance on co- and contra-variance is to use it only if doing so doesn’t involve creating extra interfaces. For instance, .Net4 introduces a readonly class called “Class Tuple(Of T1,T2)”. It is readonly, and so only uses T1 and T2 in output positions, and so they could have been marked with the Out keyword. But Tuple is a class: the only way to allow covariance would be through an extra “Interface ITuple(Of Out T1, Out T2)” which Class Tuple then inherits from. We decided not to do this: it is not worth introducing extra interfaces for the sole purpose of co- or contra-variance.

Interop with Dynamic Languages

Historically Visual Basic has been a language that provides both the safety and performance of static typing along with the flexibility of dynamic typing.  The Dynamic Language Runtime (DLR) makes it much easier for dynamic languages to interoperate with each other in such a way that each object maintains the semantics from its original language. 

Over the past few years, there has been renewed developer interest in dynamic languages (such as Python/Ruby) and their accompanying libraries/frameworks.  These languages and frameworks can use the DLR’s IDynamicObject interface to define the meanings of dynamic operations, or in the case of an API to allow direct access to an object’s properties through property syntax (a good example of this is the HTML DOM in Silverlight).

Latebinding continues to work the same way it always has in Visual Basic, but the latebinder itself has been updated to recognize when an object implements the IDynamicObject interface.  This allows Visual Basic developers to be able to fully interoperate with dynamic languages such as IronPython and IronRuby, as well as APIs that implement IDynamicObject

For example, the following code calls a method defined in the Python library “random.py”:

Dim random As Object = python.UseFile("random.py")
Dim items = {1, 2, 3, 4, 5, 6, 7}
random.shuffle(items) ' requires Option Strict Off

And this example uses one of the new DLR classes:

Dim bag As Object = New Dynamic.ExpandoObject 
bag.x = 15   ' dynamically adds a new field called “x”
bag.y = 27   ' (requires Option Strict Off)
Console.WriteLine(bag.x + bag.y)

An important use of DLR Interop is in Silverlight 4. For instance,

Dim doc As Object = Windows.Browser.HtmlPage.Document
Dim e = doc.getElementById("item") ' requires Option Strict Off
e.innerText = "hello world"

Compiling without PIAs

Using .NET to program against the Microsoft Office Object Model used to require the use of Primary Interop Assemblies (PIAs), which had to be deployed to the end-user’s machine.  These assemblies are often very large, so deploying them can often be a nuisance.

Visual Basic 10 allows these applications to be deployed without requiring PIAs to exist on the user’s machine.  It does this by generating “local types” that perform the interop calls to the COM library directly.  These types are annotated by the compiler in such a way that the Common Language Runtime (CLR) can unify these types across assemblies.  The compiler will not copy every type in the PIA into your assembly, just the ones you actually use.

In order to turn on this feature, select the reference in Solution Explorer and then set “Embed Interop Tyeps” to “True” in the Properties window:

Resources

For more information, visit the Visual Basic Team Blog (http://blogs.msdn.com/vbteam) and the Visual Basic Developer Center (http://msdn.com/vbasic).  Have fun with Visual Basic 10!