August 2007 - Posts

Welcome back to the Visual Basic 9.0 Feature Focus blog series. In this post, we'll cover the If Ternary Operator, which is a true ternary operator, something that Visual Basic has been lacking in previous releases (contrast to C-based languages' ?: operator). If there's one thing I'm sure of, it's that you - as a seasoned VB developer - have already heard of (and been using) the Iif 'function' which is known as 'Immediate IF' (official KB source):

Dim i As Integer = 123
Dim sign As Integer = IIf(i < 0, -1, 1)

In the sample above, sign will be assigned the value '1' because i < 0 evaluates to false. If the condition would evaluate to true, the second parameter '-1' would become the output result. So what's wrong with this? Nothing but the color of Iif... I'm not kidding: the problem is in the color. Iif is not a built-in function but a regular function from some library, and therefore the Iif call is like a regular function call. Function calls cause all of the arguments to be evaluated in Visual Basic. Take a look at the following and try to predict the outcome:

Sub Main()
    Dim i As Integer = 123
    Dim sign As Integer = IIf(i < 0, Negative(), Positive())
    Console.WriteLine(sign)
End Sub

Function Negative() As Integer
    Throw New Exception("Oops!")
    Return -1
End Function

Function Positive() As Integer
    Return 1
End Function

Even though we're not interested in the Negative function call, it will still happen because all arguments to Iif need to be evaluated prior to calling Iif:

image

So, if you ever read the Iif is equivalent to the following, forget about it:

Sub Main()
    Dim i As Integer = 123
    Dim sign As Integer
    If
i < 0 Then
        sign = Negative()
    Else
        sign = Positive()
    End If
    Console.WriteLine(sign)
End Sub

Instead this is what a real ternary operator should be equivalent to. Luckily we have one now in VB 9.0, and guess what: it's denoted as If too, just like its If-statement counterpart:

Sub Main()
    Dim i As Integer = 123
    Dim sign As Integer = If(i < 0, Negative(), Positive())
    Console.WriteLine(sign)
End Sub

Function Negative() As Integer
    Throw New Exception("Oops!")
    Return -1
End Function

Function Positive() As Integer
    Return 1
End Function

Trimmed of the I from IIf: color fixed and no side-effect anymore :-). But there's more to the ternary operator in Visual Basic: if it's used with only two arguments it acts as a null-coalescing operator, just as the ?? operator in C# (which was introduced in v2.0). This is especially useful if you're working with Nullable Types:

Dim name As String = Nothing
Dim nameValue = If(name, "Not set") 'will be "Not set"

name = "Bart"
nameValue = If(name, "Not set") 'will be "Bart"

Basically this use of the If operator is equivalent to:

nameValue = If(name IsNot Nothing, name, "Not set")

It works with everything that can be null, including Nullable Types:

Dim age As Integer? = Nothing
Dim ageValue = If(age, -1) 'will be -1

age = 24
age = If(age, -1) 'will be 24

Notice that the If operator requires its result operandi to be of "compatible types" so that the result type can be inferred:

image

Null coalescing proves useful if you need to switch from something nullable to something which isn't nullable but supports some kind of "default value" or "missing value".

Happy coding!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Welcome back to the Visual Basic 9.0 Feature Focus blog series. In this post, we'll cover Nullable Types, a feature that has been available in C# since version 2.0. Nullable types help to close the gap between value types and typical database representations of these, which allow values to types not to be set. There are two big categories of types in the CLS, and thus in Visual Basic too: reference types and value types. A simple of the former one is String while numerical types like Integer are samples of value types. Reference types can point to nowhere using "Nothing", while value types should have a value from their value domain (e.g. -2^32 to 2^32 - 1). So what do you do with a Customer object that has an Age property declared as an Integer but it's possible to have a missing age? Various tricks are possible: keep an additional Boolean value to indicate whether or not the value has been set, reserve a special value to indicate a value isn't set (e.g. Age = -1), ...

However, nullable types are much easier and basically wrap value types in a generic object of type Nullable(Of T) which is a structure that can have Nothing as its "value" (with aid from the compiler in case of C# - see section 6.1.5 in the spec). In fact, you could use the Nullable(Of T) class already in VB 8.0:

Dim i As Nullable(Of Integer)
Dim b As Boolean

i = Nothing
b = i.HasValue 'Will be False

i = 123
b = i.HasValue 'Will be True
Dim j As Integer = i.Value 'j = 123

However, where VB 8.0 is different from C# 2.0 is the lack of integrated syntax to denote a nullable type: you have to write Nullable(Of ...) manually each time. In VB 9.0 this has been solved:

Dim i As Integer?

The question mark is used to make a Nullable for the specified value type:

image

Notice that if a value has been assigned to a nullable variable, you can just write the following to get the value back:

Dim j As Integer = i 'j = 123

There's no need to call the Value property explicitly. If you try to get the value of an unset nullable variable, you'll get an exception thrown in your face:

image

The use of nullables goes even further by means of three-valued logic and null propagation when working with arithmetic operations on nullable value types. Take a look at the following fragment:

Dim a As Integer? = Nothing
Dim b As Integer? = 123
Dim c As Integer? = a + b

In here c will get the 'value' Nothing. Thus, whenever you apply arithmetic operations on one or more nullables of which one is null-valued (Nothing), the result will be the null value too.

Nullable types are especially useful when mapping database schemas to objects, as is done in LINQ to SQL for example. Tomorrow, we'll look at the Ternary Operator 'If' which makes working with these Nullable Types easier in some cases.

Happy coding!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Welcome back to the Visual Basic 9.0 Feature Focus blog series. In this post, we'll cover Partial Methods, a feature also available in C# 3.0 (see here). Partial methods are a logical extension to partial classes, a feature that was introduced in the VB 8.0 and C# 2.0 "Whidbey" wave. As you know, partial classes are often used in code generation circumstances, like the Windows Forms designer that puts code in a *.Designer.vb or *.Designer.cs file, while the code written by the developer is written in the other part of the partial class and kept in another code file (click to enlarge and notice the classes are declared as Partial):

image image

 image

Most likely you're aware of the fact that you should keep yourself from modifying an generated code whatsoever, since the code generator could (and will) overwrite your changes. That's why partial classes were introduced in the first place, to keep a nice separation between the code generator's stuff and your own stuff (event handlers etc in case of Windows Forms apps). In LINQ, we do have code generators too. For example the LINQ to SQL designer is responsible to generate entity classes and a data context object that can be used to write queries against the underlying data source. However, what if you'd like to add some stuff to the generated entity classes? No problem with partial classes, except for a few scenarios. Consider the following fragment to be auto-generated:

'Generated code
Partial Class
Product

    Private _name As String

    Public Property Name As String
        Get
            Return _name
        End Get

        Set (ByVal value As String)
            _name = value
        End Set
    End Property

End Class

Sure, in the another part of the partial class you can add members to this class if you'd like to do so. But what if you want to change some aspect of a member that's already there? Say you'd like to write a business rule that is executed every time the name of a product is changed. You can't change the generated code since it can be overwritten by the code generator subsequently. We're in troubles indeed. What the code generator could do however is something like this:

'Generated code
Partial Class
Product

    Private _name As String

    Public Property Name As String
        Get
            Return _name
        End Get

        Set (ByVal value As String)
            SendNameChanging(value)
            _name = value
        End Set
    End Property

End Class

However, there's no such thing as a method called SendNameChanging. In VB 8.0 and C# 2.0 such code would require this method to be present in either the generated code file (which is unlikely to be possible since an entity generator or any other code generator doesn't know about what kind of "extensions" the developer might want to add) or in another part of the partial class definition (i.e. require the developer to write such a method for each and every generated property, even if these are not required in the particular scenario the developer is faced with). The solution? Partial methods. Assume the following piece of generated code:

'Generated code
Partial Class
Product

    Private _name As String

    Public Property Name As String
        Get
            Return _name
        End Get

        Set (ByVal value As String)
            SendNameChanging(value)
            _name = value
        End Set
    End Property

    Private Partial Sub SendNameChanging(ByVal value As String)
    End Sub


End Class

In here we do have a partial method declaration. All partial methods are Private (only usable inside the same class) and marked with the Partial keyword. This is the declaration of the partial method. Now, if you'd like to implement some business rule that's triggered whenever the name of a product is changing, you can put an implementation for this method in another part of the Product partial class:

'Developer's code
Partial Class
Product

    Private Sub SendNameChanging(ByVal value As String)
        Console.WriteLine("Product name is changing to {0}", value)
    End Sub


End Class

Notice at the implementation side there's no Partial keyword on the method signature (which is different from the C# 3.0 syntax). It's important to remember that an implementation of a partial method is not required. Only if you're interested in the "extension" provided by a given partial method, you should write such an implementation. If no implementation for a partial method is found, each call to that method is ignored by the compiler, hence optimizing the code. So, if you do write an implementation the above is equivalent to:

Class Product

    Private _name As String

    Public Property Name As String
        Get
            Return _name
        End Get

        Set (ByVal value As String)
            SendNameChanging(value)
            _name = value
        End Set
    End Property

    Private Sub SendNameChanging(ByVal value As String)
        Console.WriteLine("Product name is changing to {0}", value)
    End Sub


End Class

while the following is produced when there's no implementation for SendNameChanging:

Class Product

    Private _name As String

    Public Property Name As String
        Get
            Return _name
        End Get

        Set (ByVal value As String)
            SendNameChanging(value)
            _name = value
        End Set
    End Property


End Class

So, if you don't write a partial method implementation, you don't pay any price for the method.

Happy coding!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Welcome back to the Visual Basic 9.0 Feature Focus blog series. In this post, we'll cover Expression Trees, a feature also available in C# 3.0 (see here). In the previous post of this series we did take a closer look at lambda expressions; expression trees are very closely related to lambda expressions. Simply stated, an expression tree is a data representation of lambda expression. Consider the following sample:

Dim square As Func(Of Integer, Integer) = Function(i) i * i

Note: Using Implicitly Typed Local Variables you can omit even the Func(Of Integer, Integer) part in the code fragment above. The compiler will create an anonymous delegate to represent the type of the function.

This is a very simple lambda expression that takes in an integer 'i' and produces its square value 'i * i'. So, to put a list of squares on the screen, you can write the following:

For i = 1 To 10
    Console.WriteLine("{0}² = {1}", i, square(i))
Next

As you can see, the square function can be called directly, like any other regular delegate can be called using plain simple method call syntax. In other words, the function has been fully compiled to IL code that can be executed directly at runtime. But what if we'd like to analyze the function expression at runtime? This is much more complicated but believe me there are various scenarios where this proves useful (one of which being LINQ query providers that translate expressions into some target query domain language, e.g. SQL in LINQ to SQL). Essentially, we want the compiler to translate the function from the sample above into something like this:

image

Read this tree from top to bottom: we're talking about a lambda expression that has one parameter called 'i' (left-hand side of the tree) and which has a body that produces the product (*) of 'i' and 'i' (leaf level). How can we have the compiler build this instead of regular IL-code for the function? The answer is by using the System.Linq.Expressions.Expression class, like this:

Dim square As Expression(Of Func(Of Integer, Integer)) = Function(i) i * i

Now the code fragment to produce squares won't work anymore, since square is an expression tree now:

image

Basically, whenever you assign a lambda expression to something of type Expression(Of T), either directly in a local variable or indirectly by calling a method that takes an Expression(Of T) as its argument, the compiler will produce an expression tree rather than an anonymous method for the lambda function. As a simple (!) example, consider a dynamic calculator below, which parses an expression at runtime in order to carry out the right calculation:

Imports System.Linq.Expressions

Module Demo

    Function Calc(ByVal f As Expression(Of Func(Of Integer, Integer)), ByVal i As Integer)
        If TypeOf f Is LambdaExpression Then
            Dim l = CType(f, LambdaExpression)
            If l.Parameters.Count <> 1 Then
                Throw New InvalidOperationException("Invalid number of parameters")
            End If

            Dim p = l.Parameters(0)
            If TypeOf l.Body Is BinaryExpression Then
                Dim b = CType(l.Body, BinaryExpression)

                Dim left = GetValue(b.Left, p, i)
                Dim right = GetValue(b.Right, p, i)

                Select Case b.NodeType
                    Case ExpressionType.Add, ExpressionType.AddChecked
                        Return left + right
                    Case ExpressionType.Subtract, ExpressionType.SubtractChecked
                        Return left - right
                    Case ExpressionType.Multiply, ExpressionType.MultiplyChecked
                        Return left * right
                    Case ExpressionType.Divide
                        Return left / right
                    Case ExpressionType.Modulo
                        Return left Mod right
                    Case Else
                        Throw New InvalidOperationException("Unsupported mathematical operator")
                End Select
            Else
                Throw New InvalidOperationException("Expected binary expression in function")
            End If
        Else
            Throw New InvalidOperationException("Invalid function expression")
        End If
    End Function

    Function GetValue(ByVal e As Expression, ByVal p As ParameterExpression, ByVal i As Integer) As Integer
        If e Is p Then
            Return i
        Else
            If TypeOf e Is ConstantExpression Then
                Return CType(e, ConstantExpression).Value
            Else
                Throw New InvalidOperationException("Function should only contain the function parameter or a constant value")
            End If
        End If
    End Function

    Sub Main()
        For i = 1 To 10
            Console.WriteLine("{0}² = {1}", i, Calc(Function(x) x * x, i))
        Next
    End Sub

End Module

It's a simple example because the parser is not very smart. It can just cope with simple "binary expressions" that have leafs which are either the lambda's parameter expression or a constant value. To build a really good dynamic calculator, you'll have to do much more (including the use of recursive parsing). However, it's a pretty good sample. Start by taking a look at the Main function which makes a call to Calc, passing in a lambda expression "Function(x) x * x". The reason for using 'x' is that 'i' is already in scope, but that doesn't change any meaning since it's just a dummy variable name (for math folks, that's the equivalent to α conversions in formal lambda calculus). Since the Calc method has an Expression(Of ...) as its first parameter, the compiler knows to translate the lambda to an expression tree instead of compiling it to final IL code. The Calc method itself inspects the expression tree to find out about its meaning and dynamically (at runtime) constructs the right result value. If you want to understand how it really works, debug the code above and step through the code. Also try to execute other lambdas like:

Function(x) x * 2
Function(x) x + 1
Function(x) 1 + 1
Function(x) x Mod 2

All of these should work fine.

In case you wonder where expression trees are used on an everyday basis, the answer is LINQ (to SQL for instance). If the following query is a LINQ to SQL one:

Dim res = From p In products Where p.Price > 100 Select New With { .Name = p.ProductName, p.Price }

this will get translated (lexically) into the following using extension methods (on an interface called IQueryable(Of T)) and lambdas:

Dim res = products.Where(Function(p) p.Price > 100).Select(Function(p) New With { .Name = p.ProductName, p.Price })

which is on its turn translated into:

Dim res = Queryable.Select(Queryable.Where(products, Function(p) p.Price > 100)), Function(p) New With { .Name = p.ProductName, p.Price });

These extension methods take in lambdas as Expression(Of T) objects, causing the compiler to translate them in expression trees. For instance, Function(p) p.Price > 100 becomes:

  • LambdaExpression
    • Parameters = { p }
    • Body = BinaryExpression
      • NodeType = GreaterThan
      • Left = MemberExpression
        • Property = Product.Price
      • Right = ConstantExpression
        • Value = 100

At runtime, these expression trees are parsed by the LINQ to SQL engine to translate it into the appropriate SQL fragment, for example for the total query above:

SELECT p.[ProductName] AS [ Name], p.[Price] FROM dbo.Products WHERE p.[Price] > 100

This query is sent to the server, results are fetched and the code can iterate over the produced results.

Happy coding!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Welcome back to the Visual Basic 9.0 Feature Focus blog series. In this post, we'll cover Lambda Expressions, a feature also available in C# 3.0 (see here). So, what's this feature called after a Greek letter? Lambda expressions are derived from the domain of functional programming, or in a broader sense from lambda calculus (as introduced by A. Church back in the 30s). The lambda calculus is used to define and study (computable) functions. As an example, consider the lambda definition below:

λab.a + b

which represents a function with two inputs a and b, producing a + b as its result. So, the following equals to 5:

(λab.a + b) 2 3

Enough basic theory for now, what's the use of all this in VB 9.0 (and C# 3.0). Well, consider the following example of a simple "flexible calculator" in VB 8.0:

Delegate Function Func(Of A, B, R)(ByVal a As A, ByVal b As B)

Module Calculator

    Function Calc(ByVal f As Func(Of Integer, Integer, Integer), ByVal a As Integer, ByVal b As Integer) As Integer
        Return f(a, b)
    End Function

End Module

It's flexible because the Calc method can take in a delegate to a function in order to do the real calculation. To do this, we've defined a generic delegate called Func that has two inputs, typed A and B, and an output typed R. In order to call this method, you'll have to provide a reference to a method with the right signature, like this:

Module Demo

    Function Add(ByVal a As Integer, ByVal b As Integer) As Integer
        Return a + b
    End Function

    Sub Main()
        Dim res = Calculcator.Calc(AddressOf Add, 1, 2)
    End Sub

End Module

Quite a bit of work just to call the Calc method, isn't it? What if we could write the Add function inline with the Calc call? That's exactly what lambda expressions allow you to do in VB 9.0:

Module Demo

    Sub Main()
        Dim res = Calculcator.Calc(Function(a, b) a + b, 1, 2)
    End Sub

End Module

Behind the scenes, the compiler will cook up an anonymous method that captures the lambda function (e.g. _Lambda$__1), which is equivalent to the manual approach one had to take in VB 8.0. As you can see, the compiler is smart enough to figure out the types expected for the lambda expression parameters, so you don't need to specify those (although you could if you really want to do so).

Lambdas are used extensively in LINQ queries, which are by nature pretty functional. After all, a query predicate (the "result filter") is a condition that takes in an object from the query source and produces a boolean. In other words, such a predicate is nothing more than a function of type Func(Of SourceType, Boolean). In a similar way, a query projection is a function that takes in an object from its source and produces another object (possibly an anonymous type). To illustrate this, consider a simple LINQ query (which we'll talk about in much more detail in a future post):

Dim res = From p In products Where p.Price > 100 Select New With { .Name = p.ProductName, p.Price }

This gets translated (lexically) into the following using extension methods and lambdas:

Dim res = products.Where(Function(p) p.Price > 100).Select(Function(p) New With { .Name = p.ProductName, p.Price })

Notice I can't tell the type of the res variable (I'm looking Implicitly Typed Local Variables), in this case it's something like IEnumerable(Of AnonymousTypeOfTheProjection) - strictly spoken it can be an IQueryable(Of ...) too, which I'll discuss in subsequent posts.

Lambdas can be used for expressions only, you can't embed statements in a lambda's body (like Console.WriteLine): lambda functions take in some data and produce other data, that's it. As an exercise, predict the output of the following:

Console.WriteLine((Function(a, b) a + b)(1, (Function(c, d) c * d)(2, 3)))

In lambda calculus terms, this comes down to a technique called "ß-reduction".

Happy coding!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Welcome back to the Visual Basic 9.0 Feature Focus blog series. In this post, we'll cover Anonymous types, a feature also available in C# 3.0. The need for anonymous types originates from projection clauses in LINQ statements which typically cook up a new ad-hoc type containing the data of interest. Nevertheless, anonymous types are useful in isolation too, for instance to group a couple of variables together without having to build a special type for that sole purpose.

Anonymous type syntax is similar to Object Initializer syntax (see previous post in my Visual Basic 9.0 Feature Focus series) and looks like this:

Dim t = New With {.Name = "Bart", .Age = 24}

The part between the curly braces can contain an arbitrary number of initializers which follow the syntax conventions of With (i.e. starting with a dot). Notice this is a place where Implicitly Typed Local Variables are required in order to declare a variable of the anonymous type (which has some compiler-generated unspeakable name like VB$AnonymousType_0`2).

image

Notice the type overrides ToString which produces a comma separated key/value pair string between curly braces, like "{ Name = Bart, Age = 24}". The compiler is also smart enough to infer the name of the to-be-generated property if you're referring to another already-existing property, like this:

Dim t = New With {.Name = "Bart", .Age = 24}
Dim id = 123
Dim u = New With {.Id = id, t.Name, t.Age}

where the latest statement is equivalent to:

Dim u = New With {.Id = id, .Name = t.Name, .Age = t.Age}

One thing unique to VB 9.0 is the existence of so-called keyed anonymous types. In the previous samples, the Equals method will only return true if you're comparing two identical references with one another. Therefore, the following will print False:

Dim t = New With {.Name = "Bart", .Age = 24}
Dim u = New With {.Name = "Bart", .Age = 24}
Console.WriteLine(t.Equals(u))

even though both anonymous types denote the same "shape" and have the same values assigned. If you define one or more properties as a key using the Key keyword (that's a lot of keys in this sentence), these are used for the equality check (Equals) and the creation of a hash code (GetHashCode). Here's a sample that will print True:

Dim t = New With {Key .Id = 1, .Name = "Bart", .Age = 24}
Dim u = New With {Key .Id = 1, .Name = "Anders", .Age = 47}
Console.WriteLine(t.Equals(u))

Both objects are the same because (all) the keys are equal: only the fields marked with Key are compared to do the equality test. Geeks can check this easily using ILDASM.

We'll encounter anonymous types again when talking about LINQ query syntax later in this series. A little sample of a projection inside a VB 9.0 LINQ query is shown below:

Dim res = From c In customers Select New With {c.Name, c.Age}

Happy coding!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Welcome back to the Visual Basic 9.0 Feature Focus blog series. In this post, we'll cover Object Initializers, a feature also available in C# 3.0 (see here). The problem this feature aims to fix is the following: how many times did you need to use some type and did you find youself looking at the constructor overload list to come to the conclusion the overload you'd like to have is missing (or maybe there's just a default parameterless constructor). So, in lots of cases you need additional properties to be set after calling a somewhat appropriate constructor. Let's give an example below:

Class Customer

    Private _name As String
    Private _age As Integer

    Public Sub New(ByVal name As String)
        _name = name
    End Sub

    Public Property Name() As String
        Get
            Return _name
        End Get

        Set(ByVal value As String)
            _name = value
        End Set
    End Property

    Public Property Age() As Integer
        Get
            Return _age
        End Get

        Set(ByVal value As Integer)
            _age = value
        End Set
    End Property

End Class

In order to construct an object of the type, you'll typically do something like this:

Dim c As New Customer("Bart")
c.Age = 24

or, especially if you have to set multiple properties,

Dim c As New Customer("Bart")
With c
    .Age = 24
End With

I think everyone agrees initialization logic should be kept together, but the need for multiple initialization statements can complicate matters (what if someone inserts something between line one and two?). So a more convenient initialization syntax was added to Visual Basic 9.0 (and C# 3.0) to help with this:

Dim c As New Customer("Bart") With {.Age = 24}

With the aid of IntelliSense you get the following:

image

The With portion of the object initializer takes a comma separated list of initialization statements that can be used for all accessible fields and properties. You can split the initialization statement over multiple lines of code using the line continuation _. It seems Visual Basic got curly braces at last :-).

Happy coding!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Welcome back to the Visual Basic 9.0 Feature Focus blog series. In this post, we'll cover Extension Methods, a feature also available in C# 3.0 (see here). Extension methods allow you to "extend" an existing type with an instance method, at least virtually. That is, in reality an extension method is a Module's Shared method or function, but which can be called with instance method call syntax. Consider the following problem in VB 8.0:

Dim s As String = "Bart De Smet"
Dim t = s.ToLower().Reverse().Substring(0, 4)

The problem in the fragment above is the lack of a Reverse instance method on System.String. A possible solution is to write a helper method like this:

Module MyExtensions

    Function Reverse(ByVal s As String) As String
        Dim c As Char() = s.ToCharArray()
        Array.Reverse(c)
        Return New String(c)
    End Function

End Module

which can be called like this:

Dim s As String = "Bart De Smet"
Dim t = MyExtensions.Reverse(s.ToLower()).Substring(0, 4)

This is quite counterintuitive because the Reverse call is moved to the front of the method call chain. Because System.String is sealed and you typically don't have the code available for 3rd party libraries to put the extension in there, you're restricted to a shared function. However, in VB 9.0 you can declare the method as an extension method, like this:

Imports System.Runtime.CompilerServices

Module
MyExtensions

    <Extension()> _
    Function Reverse(ByVal s As String) As String
        Dim c As Char() = s.ToCharArray()
        Array.Reverse(c)
        Return New String(c)
    End Function

End Module

Now you can write the following:

Dim s As String = "Bart De Smet"
Dim t = s.ToLower().Reverse().Substring(0, 4)

Internally, this gets translated into this (as in our manual VB 8.0 code fragment):

Dim s As String = "Bart De Smet"
Dim t = MyExtensions.Reverse(s.ToLower()).Substring(0, 4)

Notice that the method shows up in the IntelliSense method list and is marked as an <Extension> together with a slightly different icon (the blue arrow indicates the method is an extension).

image

Extensions are brought in scope by means of namespaces. Assume the extensions module is defined in a namespace, like this:

Imports System.Runtime.CompilerServices

Namespace Sample


    Module
MyExtensions

        <Extension()> _
        Function Reverse(ByVal s As String) As String
            Dim c As Char() = s.ToCharArray()
            Array.Reverse(c)
            Return New String(c)
        End Function

    End Module

End Namespace

then you can bring the Reverse extension method in scope by writing the following:

Imports Sample

Extension methods can be either a Sub or a Function and have at least one parameter, which is the one that becomes the left-hand side of the instance method invocation syntax:

image

You can add as many parameters you want after the special-treated first parameter; these become the "real parameters" used when calling the method using instance method invocation syntax:

Module MyExtensions

    <Extension()> _
    Sub Bar(ByVal s As String, ByVal a As Integer, ByVal b As Integer, ByVal c As Integer) As String

    End Sub

End Module

can be called like this:

Dim s As String = "Bart De Smet"
s.Bar(1, 2, 3) 'equivalent to calling MyExtensions.Bar(s, 1, 2, 3)

Extension methods can be defined on classes, structures and interfaces and can use most parameter list features that Visual Basic offers, except for an Optional or ParamArrays first parameter. Also, make sure your extension methods are CLS compliant so that these can be used from other languages too (like C# 3.0).

Happy coding!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Welcome to my first post of the Visual Basic 9.0 Feature Focus blog series. In this post, we'll cover Implicitly Typed Local Variables, a feature also known as Local Variable Type Inference in the C# 3.0 world. So, what's it? Consider the following fragment in VB 8.0:

Dim i As Integer = 123
Dim s As String = "Bart"
Dim d As Dictionary(Of String, List(Of Integer)) = New Dictionary(Of String, List(Of Integer))

As you can see, there's quite some verbosity in the code fragment above. Why do we have to tell the compiler i is an integer if the right-hand side of the expression does the same (123 is an integer after all). Similar remarks hold true for the string s and especially for the (complex) Dictionary in the last line of code. Right, that last line could be abbreviated to

Dim d As New Dictionary(Of String, List(Of Integer))

But still, the verbosity is there for the other cases. What if you could write the following instead?

Dim i = 123
Dim s = "Bart"
Dim d = New Dictionary(Of String, List(Of Integer))

To show that you don't use any of the type information, take a look at the IntelliSense for say s:

image

That looks pretty much like the IntelliSense for a String variable, isn't it? That's because s is still known to be a string by the compiler, you don't lose any of the type information: the type of the local variable is inferred. Visual Basic 9.0 has one thing more than the C# 3.0 feature counterpart, which is an option to enable/disable this type inference mechanism: Option Infer.

image

For new projects, this option will be on by default. You can also set this option application-wide through the project properties Compile tab:

image

If you put Option Infer to Off, you'll get the following result:

image

The objects look as if they are typed at System.Object, but in reality you're switching to late binding right now:

image

If you want to keep Option Infer On but you'd like to have a variable to be late bound for some reason, you can use the following:

image

That is, declare the variable As Object. Needless to say so, late binding will only work if Option Strict is set to Off.

You might wonder whether this feature is so important. The answer is that Implicitly Typed Local Variables are optional in most cases, but in one scenario the use of it is mandatory: when you're using anonymous types, a feature I'll blog about later on in this series.

Happy coding!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

It seems a little weird for a C# MVP to start a series on VB 9.0 Language Enhancements, isn't it? However, I have a strong passion of the CL in CLR and CLS: Common Language. Therefore, I'll focus in this blog series on various language enhancements that ship with VB 9.0 as part of the .NET Framework 3.5 and Visual Studio 2008 release wave. If you're more of a CSharpish guy or girl, check out my C# 3.0 posts. For Belux folks, I'll be giving a talk on Visual Studio 2008 and .NET Framework 3.5, also covering language enhancements quite extensively, in Luxembourg in September (the exact date will be published in the upcoming weeks).

Some features I'll cover in this series are:

  • Implicitly Typed Local Variables
  • Extension Methods
  • Object Initializers
  • Anonymous types
  • Lambda Expressions
  • Expression Trees
  • Partial Methods
  • Nullable Types
  • The If Ternary Operator
  • Friend Assemblies
  • Relaxed delegates
  • Runtime Agility
  • XML support
  • LINQ query syntax

I hope you'll enjoy this rollercoaster ride on the VB 9.0 wagon.

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

More Posts Next page »