Friday, February 17, 2006

Upgrade Fun - Moving to VS2005

Following on from my first post, we are now starting to upgrade for real and trying to get rid of those warnings. This is being hampered by the background compiler: every time I fix up a bit of code off it goes, hogging my CPU, until it has gone through the entire solution I guess. A search on the MSDN forums turns up this from MS guy Matthew Gertz:

"The background compiler cannot be turned off in Visual Basic .Net – it’s actually the thing that’s providing all of the Intellisense information, formatting information, and so on. I discuss this in some detail here. In that article are some tips to improve performance in larger-scale applications."

To minimize this problem, I am opening our projects one by one (bottom-up in the reference tree) instead of all at once in our monster solution. In fact, I think our development is going to have to continue this way until the background compiler's performance (or at least its perceived performance) is greatly improved.

Using an instance variable to access a shared member (Error ID: BC42025)

I would like to turn this warning off rather than fix it, because using a short
variable name in place of a sometimes quite long class name can reduce clutter and
make the code easier to read. However one of the ways we do this is we declare an
instance of an enum type (nested in another class) to provide short-cut access to
the enum literals, which results in an "unused variable" warning which I definitely
don't want to turn off.

Fortunately, initializing the enum variable removed the "unused" warning, at least in this compiler version. This is fortunate because the warning was also occurring when accessing members of the DialogResult enumeration on a form: Form also has a DialogResult property which hides the enum so you end up having to fully qualify it (or partially qualify it if you import a parent namespace, e.g. System.Windows).

Getting out of bad VB6 habits, and other details

The new compiler is much more fussy (a Good Thing) at pointing out poor form, including:

  • Not explictly initializing reference variables if they are going to be used before an assignment;

  • Not explictly returning Nothing from a function (a variant of this is having return statements inside a Select - you're then forced to define an "else" clause, which is another Good Thing);

  • Leaving unused variable declarations lying around.

Mind you, the explicit initializer thing is a bit of a pain when you're only going to initialize it to Nothing anyway. I've gotten too used to seeing lack of an initializer as an invisible Nothing or 0 (note the compiler doesn't fuss about default initialization of value types - why the inconsistency?) Also, the parser doesn't recognize patterns such as this, and reports that ref is used before being initialized:

Dim isFirstTime As Boolean = True
Dim ref As SomeClass
For i As Integer = 0 To 10
If isFirstTime Then
ref = SomeMethod()
isFirstTime = False
'use ref
End If

Another annoying variant of this is "Variable 'XXX' is passed by reference before it has been assigned a value. A null reference exception could result at runtime." This is annoying when you are passing by reference because the method is going to initialize the variable. This is a weakness of ByRef in VB: it means "in/out" and we have no keyword to specify just "out".

Proper XML commenting - Hooray!

We had had a half-hearted attempt to add these in using the VBCommenter add-in in Visual Studio 2003, but stopped when we found Intellisense wasn't picking up our descriptions. We've now got to fix syntax errors (invalid whitespace), mismatched param elements etc. in the existing comments.

I am getting a strange error though: "XML documentation parse error: "Whitespace is not allowed at this location. XML comment will be ignored." This is being reported inside the summary element. I.e. I can cut all the lines between <summary> and </summary> and it is fine, but when I paste the original text back (which contains no XML or anything obviously funky), the error springs back.

D'oh - the summary text contained an ampersand! So it seems like it is a real XML document fragment.

Inappropriate use of 'Overloads' keyword in a module

This surprised me. The help link merely says that modules aren't classes and therefore can't use MustInherit etc., blah, blah. Nothing about why Overloads is invalid on Module members. You can use it on Shared class members, so what's the problem? Amanda Silver explains:

We decided to give this warning because the application of the Overloads keyword only makes a difference to the semantics of the application when the method is overloaded across an inheritance chain. As the Overloads is superfluous in the context of a Module (and possibly misleading) we decided to emit a warning. Note, however, that the warning can be turned off by going to the project properties and selecting the "Disable all warnings" check box.

I love the last sentence!

I need to revise the purpose of Overloads and Shadows to fully understand this, but I would have thought that if you get a warning for Module members, you should get one for Shared class members too. Stay tuned.

Name '_blah' is not CLS-compliant

In a number of places, we have protected fields which, because they are fields, begin with an underscore. Because protected members are exposed outside the assembly and therefore available to other assemblies, they should be CLS-compliant (which means they can't begin with an underscore). The easiest way round this, since we don't need to interop with other .NET languages, is to mark the entire assembly as not CLS compliant in Assembly.vb.

Keeping Your Friends Close

I don't like the "Friend" access modifier in VB.NET ("internal" in C#) because it provides a very sloppy kind of access control, allowing as it does any method in the entire assembly to access the Friend type or member.

In C++ you could (I suppost "can" would be better, but I don't think I'll be using C++ very much in the future) explicitly specify who your friends are, to the class or even method (or top-level function) level, which means you keep control over the interfaces to your class.

From a library writer's perspective (when looking at the library as a whole at least), Friend is somewhat useful because it lets you separate "us" from "them", but when you're writing in-house code and trying to design coherent public and proptected interfaces, Friends can become your enemies.

Especially since we are encouraged to write "big" assemblies to reduce load times and so can't use the assembly as a fine-grained partitioning mechanism for tightly coupled classes.

What would be nice is a namespace-like mechanism to allow you to group classes together into friendships, so that only classes in the same friendship group have access to each other's Friend members.

Namespaces themselves can't be used of course, because anyone can add additional types to a namespace.

But you could say that Friend members where only accessible from type in the same assembly and namespace. Or, better, allow the Friend keyword to be used on a namespace declaration to mean "Friends within this namespace aren't accessible outside it" (obviously the "same assembly" restriction would still hold). The good thing with this approach is that if you don't use it you get the current behaviour.

What do you think Mr. Vick?


Having proudly e-mailed Paul Vick my suggestion, I blushingly realized that what I should have done is enter it via the "Make a Suggestion" link on the MSDN product feedback page. When I started to do that I found several other suggestions along the same lines (i.e. reintroducing C++ style friend specifiers), but none I think as simple as mine, although I have conveniently ignored how these friend namespaces should be managed across multiple source files in the same assembly - i.e. should you be made to specify "friend" for all of them, or should doing it once automatically apply to all; perhaps it is analagous to partial classes. Also I didn't think of the work that would be needed in the CLR; after all, namespaces are just syntactic sugar, right? Yeah, but friend/internal isn't! Sometimes I wish I'd just keep my (e-)mouth shut.

Update #2

Paul Vick replied on 26th Feb:

Hey, Ian, I apologize for taking so long to write back! More granular Friend control is definitely something that's been requested in a number of different ways and it's something we'll definitely look at as we plan our next release. It's definitely a matter of trying to balance the need for control versus the need to keep the concept count down as much as possible, always a delicate trade off.
Thanks for making the suggestion and thanks for using VB!

Tuesday, February 14, 2006

Synchronize Class View in VS2005

Wanted to give this some more Google-juice (though I don't think even the Google spider reads my blog) because the help docs lie:

A Quote for New Bloggers

When you start a blog it is with high hopes that your fantastic insight and wit will garner a steadily growing readership, with occasional rapid rises when some blog-ebrity links to you from his blog.

Sadly this is not generally the case, and you either give up in defeat, or relegate your blog to a personal diary. Alternatively you can image that there really are hundreds, nay thousands, of appreciative readers who are just too shy to leave comments.

With a few notable exceptions (see, a good blogger would put some links in here) most of the popular blogs out there are popular because they are written by well-known speakers or authors (and I'm being parochial here, I've no idea what happens in blogs I don't read).

And here's why (and finally the point of this post):

P.S. if anyone is reading this blog, please excuse posts mysteriously appearing "in the past"; I'm pulling stuff together that I've already posted elsewhere, or queued to post, and I want to keep the original dates on stuff. This is a personal diary after all!