Author Archives: paulvick

Nice words for My…

Jesse Liberty has written a very nice article on My for O’Reilly’s OnDotnet.com. He starts with a theme we’ve seen a lot of over the years:

For a couple of years now, I’ve been touting the Microsoft-endorsed sentiment that it really doesn’t matter if you program in C# or in VB.NET, since both are just syntactic sugar layered on top of MSIL (Microsoft Intermediate Language, the true language of .NET).

But then adds:

That appears to be changing a bit with Whidbey.

He then talks about some of the features you’ll get with My. He concludes with:

The My object has made creating this application almost absurdly easy. […] VB 2 has taken a dramatic lead in Rapid Application Development with the My object.

Go check it out!

Custom events

In my previous entry on events (written well before even VS 2002 had shipped), I made the comment:

VB does not have a syntax for defining events that allows you to specify the field, the add method or the remove method. Those are always implicitly generated.

Now, most of the time this doesn’t really matter. Most of the time, the code you write in the add and remove method is going to be the same boilerplate code over and over and over again, so you’re going to want to just let the compiler do its thing and not worry about it too much. However, there are some situations in which you might want to take over managing an event’s delegate. The most common case that I know of is the situation in which you have an object that raises a lot of events. For example, a Form can raise something like 85 different events. If you accept the default compiler behavior, this means that the compiler will generate a field for each and every event to store the event handlers for that event. Which means in the case of Form, that it would generate something like 85 fields, even though in most cases programmers only ever handle about 4-5 events on a Form!

One alternative to wasting all that space is to use a hashtable to store delegates for just the events that someone is handling. To do this, though, you need to be able to control what happens when someone hooks up to or unhooks from an event. So, in VB 2005, we’re introducing something we call custom events that look something like this:

Class C1
    Public Custom Event MyEvent As EventHandler
        AddHandler(ByVal d As EventHandler)
            ...
        End AddHandler

        RemoveHandler(ByVal d As EventHandler)
           ...
        End RemoveHandler

        RaiseEvent(ByVal o As Sender, ByVal e As EventArgs)
            ...
        End RaiseEvent
    End Event
End Class

Custom events are declared with the Custom modified on the event declaration and have to explicitly state their delegate type. Custom events have three parts: an AddHandler method that is called when someone is hooking up to the event, a RemoveHandler method that is called when someone unhooks from the event and a RaiseEvent method that is called when the class does a RaiseEvent on the event. The AddHandler and RemoveHandler methods take a delegate of the type of the event. The RaiseEvent method takes the same parameters as the event delegate does. So, to store all event delegates in one hashtable, you could do the following:

Class C1
    Private EventDelegates As New Dictionary(Of String, EventHandler)

    Private Sub AddNewHandler(ByVal eventName As String, ByVal handler As EventHandler)
        If EventDelegates.ContainsKey(eventName) Then
            EventDelegates(eventName) = CType([Delegate].Combine(EventDelegates(eventName), handler), EventHandler)
        Else
            EventDelegates(eventName) = handler
        End If
    End Sub

    Private Sub RemoveExistingHandler(ByVal eventName As String, ByVal handler As EventHandler)
        If EventDelegates.ContainsKey(eventName) Then
            EventDelegates(eventName) = CType([Delegate].Remove(EventDelegates(eventName), handler), EventHandler)
        End If
    End Sub

    Private Sub RaiseOneEvent(ByVal eventName As String, ByVal sender As Object, ByVal e As EventArgs)
        If EventDelegates.ContainsKey(eventName) Then
            Dim p As EventHandler = EventDelegates(eventName)

            If p IsNot Nothing Then
                p.Invoke(sender, e)
            End If
        End If
    End Sub

    Public Custom Event MyEvent As EventHandler
        AddHandler(ByVal d As EventHandler)
            AddNewHandler("MyEvent", d)
        End AddHandler

        RemoveHandler(ByVal d As EventHandler)
            RemoveExistingHandler("MyEvent", d)
        End RemoveHandler

        RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)
            RaiseOneEvent("MyEvent", sender, e)
        End RaiseEvent
    End Event
End Class

One thing to notice that’s different from C# is that we make you specify a RaiseEvent method. This is to enable the RaiseEvent statement, which C# doesn’t have, to work properly. Otherwise, it works pretty much the same way C#’s event declaration does.

More upcoming chats

The VB team blog has listed the upcoming team chats, but I thought I’d also put in a word for one I’m going to be participating in. Also, if there are any topics that you’d like to see, just leave a comment and I’ll pass it along!

Visual Basic 2005 Language Enhancements
Visual Basic 2005 has many new and improved language features, including generic types, operator overloading, compiler warnings, partial classes, mixed access properties, unsigned data types, and more. Join members of the Visual Basic team to discuss these features. Provide the team with your feedback about the Beta version and get answers to your questions.

August 12, 2004
1:00 – 2:00 P.M. Pacific time
4:00 – 5:00 P.M. Eastern time
20:00 – 21:00 GMT
OutlookAdd to Outlook Calendar
FriendTell a Friend

How Events Work in VB (and some side info on .NET events in general)

Mike asked me what event properties are, but before I can really talk about them, you need to understand how events work in VB and .NET. Rather than write up a whole new, long entry, I think I’m just going to reprint an email that I sent to the dotnet@discuss.develop.com alias nearly four years ago. (Wow, has it really been that long?) Then tomorrow or so, I’ll talk about what we’re doing new in VB 2005. So, the following is what I wrote, with some minor clarifications and corrections:

Since the method of doing events is different in .NET than it is in COM2, I wrote up an internal memo about how events work and specifically how they work in VB (since VB has a few extra shortcuts that languages like C# don’t). I though I would forward it along if anyone is interested. This presupposes a little knowledge of .NET and VB, but not much. This is also very VB-specific. Details may be different for other languages such as C#, but keep in mind that events in all .NET languages are built on the same foundation and are totally interoperable.

Step 1: Delegates

The foundation of events in the .NET Framework is delegates, which can be thought of as type-safe function pointers. A delegate is defined by a subroutine or function signature. Using the AddressOf operator, you can capture the address of a subroutine or function that matches that signature in a variable whose type is the delegate type. Once you’ve captured the address of a method in a delegate, you can pass the delegate around as you can any object. You can also use a delegate variable as if it was a subroutine or function to invoke the method pointed at by the delegate. For example:

Delegate Function D1(ByVal intvar As Integer) As Integer

Module M1
Function F1(ByVal intvar As Integer) As Integer
F1 = intvar
End Function

Sub Main()
Dim d As D1 = AddressOf F1
Dim intval As Integer = d(10)

Console.WriteLine(intval) ' Will print out "10"
End Sub
End Module

Delegates have two special properties. First, delegates allow you to take the address not only of shared methods but also of instance methods. In the case of an instance function, both the function address and object instance are stored, allowing for correct invocation of virtual functions. The second special property is that delegates are combinable. When you combine two delegates (which must be of the same delegate type), invoking the resulting delegate will call both delegates in order of combination. This is necessary for events to work, as we’ll see below. Combining delegates that have return types is possible, but the return value of the delegate invocation will be the return value of the last function invoked.

Interoperation Note: VB allows syntactic shortcuts when creating delegates. From the .NET perspective, creating a delegate involves invoking a constructor on the delegate class that takes an object instance (possibly Nothing for shared methods) and the address of a method. So in C#, creating a delegate looks something like “new deltype(objvar, method)”. This syntax is usable in VB, except we require that taking the address of a method be done explicitly and don’t require the object instance (inferring it instead from the reference to the method) – i.e. “new deltype(AddressOf objvar.method)”. In most cases, however, you can just say “AddressOf objvar.method” and VB will infer what delegate type to instantiate based on the target type of the expression. In the case where the target type is ambiguous – “Dim o As Object : o = AddressOf method” – a compile-time error will be given. [Ed note: I believe C# is adding this feature in C# 2005, but I could be wrong about that.]

Step 2: Events (.NET style)

Once we have delegates, events become possible. An event raised by a class is defined by three things: a delegate type, an add listener method and a remove listener method. The delegate type defines the signature of the event handler – in other words, the delegates define the arguments that will be passed to a method that gets called when the event occurs. The add and remove listener methods allow other objects to start and stop listening to the event. The add listener method takes a parameter of the event delegate type and combines it with any other delegates that may be listening to the event. The remove listener method takes a parameter of the event delegate type and removes it from the list of delegates listening to the event. When the object wants to fire the event, it just invokes the delegate. For example:

Class EventRaiser
' The event delegate
Public Delegate Sub ClickEventHandler(ByVal x As Integer, ByVal y As Integer)

' The list of objects listening to the event
Private ClickEventHandlers As ClickEventHandler

' The add and remove methods
Public Sub add_Click(ByVal handler As ClickEventHandler)
System.Delegate.Combine(ClickEventHandlers, handler)
End Sub
Public Sub remove_Click(ByVal handler As ClickEventHandler)
System.Delegate.Remove(ClickEventHandlers, handler)
End Sub

' Some method that fires the event
Public Sub OnClick(ByVal x As Integer, ByVal y As Integer)
ClickEventHandlers(x, y)
End Sub
End Class

Class EventListener
Public e As EventRaiser

Private Sub HandleClick(ByVal x As Integer, ByVal y As Integer)
...
End Sub

Sub New()
e = New EventRaiser
' Hook up to the event
e.add_Click(AddressOf Me.HandleClick)
End Sub
End Class

Step 3: Defining Events (VB.NET style)

The above example, although it shows how events work, does not actually define an event in VB. Events are defined by specific metadata and not just a design pattern. To define an event in VB, there are two syntaxes you can use:

Event Click(ByVal x As Integer, ByVal y As Integer)

This event syntax does the most for you. It implicitly defines all of the code you see in EventRaiser except for the method that raises the event.

Event Click As ClickHandlerDelegate

This event syntax allows you to reuse an existing delegate type as the type of the event. This is useful if you have a number of events that all take the same set of parameters. This still defines the field, the add method and the remove method.

VB does not have a syntax for defining events that allows you to specify the field, the add method or the remove method. Those are always implicitly generated. [Ed note: For those of you who are thinking ahead, this is what we’re changing in VB 2005.]

Step 4: Handling Events (VB style)

Although it is legal to call the add handler method when you want to handle an event raised by an object, as in the example above, VB provides a cleaner syntax to do so. The AddHandler and RemoveHandler statements will take care of calling the add and remove methods with the proper values. For example:

Class EventListener
Public e As EventRaiser

Private Sub HandleClick(ByVal x As Integer, ByVal y As Integer)
...
End Sub

Sub New()
e = New EventRaiser
' Hook up to the event.
AddHandler e.Click, AddressOf Me.HandleClick
End Sub
End Class

In other languages, this is the extent of their support for handling events – the developer has to explicitly hook up to and unhook from events. VB provides another way to hook up to events – declarative event handling – that is in many ways more convenient.

Declaratively handling events is a two step process in VB. First, the object that is going to rais
e the events must be stored in a field with the WithEvents modifier, which indicates the field’s availability for declarative event hookup. Then, methods can state that they handle a particular event raised by the field by specifying a Handles clause and giving the field and event handled. For example:

Class EventListener
Public WithEvents e As EventRaiser

Private Sub HandleClick(ByVal x As Integer, ByVal y As Integer) Handles e.Click
...
End Sub

Sub New()
e = New EventRaiser
End Sub
End Class

It is important to step back for a moment and discuss what happens behind the scenes with the above syntax. When a field is declared as a WithEvents field, the field is changed into a property at compile time. This allows the event hookup to be performed whenever the field is assigned to. The Get part of the property just returns the value of the field. The Set property first unhooks any declarative event handlers from the current instance in the field (if any), assigns to the field, and then re-hooks up any declarative event handlers to the new instance. This is what the above code is transformed to under the covers:

Class EventListener
Private _e As EventRaiser

Public Property e As EventRaiser
Get
Return _e
End Get
Set
If Not _e Is Nothing Then
RemoveHandler _e.Click, AddressOf Me.HandleClick
End If
_e = Value
If Not _e Is Nothing Then
AddHandler _e.Click, AddressOf Me.HandleClick
End If
End Set
End Property

Private Sub HandleClick(ByVal x As Integer, ByVal y As Integer)
...
End Sub

Sub New()
e = New EventRaiser
End Sub
End Class

Note that while declarative event hookup can be very convenient, it does have limitations. First, you can’t declaratively handle events raised by objects not stored in a WithEvents field. Second, you can’t declaratively handle shared events, since they are not tied to an instance that can be assigned to a WithEvents field. And third, you can’t control when the event is hooked up to or unhooked from. For all of those cases, you must use dynamic event handling.

Time ever marches on…

Now that VB 2005 Beta 1 has shipped, the time has come to start doing some “long lead” work on versions beyond the 2005 release. What this means is that while 98% of the team remains focused full-time on finishing the current product, a few people get to start spending some of (though hardly all of) their time thinking about the kinds of big issues that we might want to solve in the next version(s). A good way of thinking about it is that before a version ships we try to lay some of the groundwork for the next release so that when the rest of the team is ready to engage on the next version down the road, we can hit the ground running. (Other teams are also starting to do some of this work, too.)

At the moment, I’m spending my long lead time thinking about two major things. One is: what can we learn from scripting languages? We sort of discussed this back in March, and now I’m returning to the question, both in terms of the question of development environment and in terms of the question of dynamism. (Which is also interesting given that the CLR hired a scripting language implementer specificially to work on making the CLR better for dynamic languages.) The other is: what can we do to improve data access? This is something that other languages are thinking about as well. My interest stems not just from the fact that people find it difficult at times, but from the fact that my first job at Microsoft involved working a lot with SQL and data access (I worked on the query designer in Access) and I’d like to see us improve in that area.

Those are just the two things that I’ve started with, but there’s certainly room for other things as well. What other things would you like to see? I’m not talking about features (you can go submit those requests here and the product teams will see them), I’m talking about big picture areas like the ones I mentioned above. What areas do you think we could do better in? What areas do you think there is untapped potential? Can’t promise I’ll look at everything, but I’m curious to see what people might be thinking.

(Since we MSFT bloggers often get dinged for talking only about the future and never about the present, I should add the disclaimer that I don’t plan on talking too much about this long lead work for the forseeable future. This blog is still going to properly remain focused on VB 2003 and VB 2005, not on random ideas about the future that may or may not ever come to fruition. There’s been way too much of that at Microsoft in the past.)

We are experiencing technical difficulties, please stand by…

As I’ve said before, I host my own website which means that I’m responsible for my own DNS resolution. For a long time, I used the free service provided by Granite Canyon as a secondary DNS server, however that service started becoming more and more unreliable this year and appears to be largely dead. Searching for another source of secondary DNS hosting, I hit upon secondary.org, which seemed like a good place to get some free backup DNS hosting. Big mistake.

Sometime over the weekend, it appears that secondary.org has been taken over by someone who’s started redirecting all DNS requests to some random website. Depending on which DNS server your machine chooses when resolving panopticoncentral.net, you’ll either get my website or not. Last night I moved all my DNS hosting over to Network Solutions which at some point started offering free DNS hosting to people who register with them (all the better to sell their web and mail hosting). As that change propagates itself throughout the DNS system of the Internet, the connection to this server should become reliable again. I apologize to everyone who’s been redirected against their will…

Why no ++ and –, redux

Since we’re on the subject of language differences today, it’s worth noting that Eric Lippert wrote his own entry on why he thinks VB shouldn’t have ++ and —. I’m not sure if he saw my original thoughts on the subject, but it’s interesting to see the similiarities and differences in reasoning. Eric also privately asked me about a different reason for not requiring Partial on partial types, but I’m going to cover that later this week – I’ve blogged enough for today.

Language harmony

In the comments to my previous entry on partial types, mustTryHarder comments:

If C# always uses the partial keyword (and presumably went through the same level of debate) then why did the VB team approach it differently? I assume you guys talk to each other. I can’t see how Microsoft can justify a difference. While virtually everyone agrees that separation of designer code is desirable, it would appear that only the VB team feel the Partial keyword is optional. IMHO the VB team would do well to listen to feedback on syntax in order to avoid the same back-tracking in future that happened with areas such as properties which are now once again able to specify different accessibility levels for Get/Set. So far your private debates have got it wrong!

mustTryHarder’s comments are contradictory, although there was no way for him to know that ahead of time. You see, the reason why VB didn’t support properties with different levels of accessibility in VB 2002 and VB 2003 is because the C# team didn’t want to support them. Our original plan was to include them just the way they were in VB6 but the C# design team was very definite that they thought they were a bad idea and that they weren’t going to include them in their language. As a result, when the C# compiler came across a property with different levels of accessibility, they would consider the property’s accessibility to be the more restrictive of the two. So if we’d gone ahead and implemented the feature anyway, a property with a Public Get and a Private Set would have been considered Private by C#, which would have looked a lot like a bug to most people. So we made the decision to not implement the feature in the interest of playing well on the .NET platform. Fortunately, everyone’s come around in VS 2005, so the feature is going to appear in both languages and there aren’t going to be any difficulties.

So, ironically, in this case we’re getting simulateously criticized for not doing the same thing as C# is doing and for doing the same thing as C# did. Welcome to the world of multi-language programming on the .NET platform, folks. We’re not in Kansas anymore.

The truth is, we have a lot of regular contact with the C# team about design decisions and feature choices and, where it makes sense, we try and be harmonious. However, each language’s design team has distinct visions for their language and that is inevitably going to cause divergence. For example, I know that more than a few people on the C# team (and more than a few C# users) think that our generics syntax is stupid. I can see where they might be coming from in having that opinion, but I disagree with it… and that’s the way it goes. Should VB users not get Edit and Continue because the C# team doesn’t think that it’s important enough to ship in VS 2005? Should C# users not get iterators because VB doesn’t think that it’s important enough to ship in VS 2005? Who gets to decide which vision is the “right“ one? Who’s even to say that there is a single “right“ vision for the millions and millions of developers out there in the world?

I should be clear that what I’m not saying is that people shouldn’t feel free to complain loudly about things that they don’t like about VB. That feedback is invaluable and helps guide the future direction of the language. What I am saying, though, is that one argument that is never going to work with us is “But C# does it differently and you both should do everything the same way!” If there are concrete reasons why you think the C# design is better, then let’s hear them and we can have a good discussion about the merits and demerits of the VB approach. Otherwise…