CodeThinked

codethinked (kōdthĭngked) adj. To be consumed by or obsessed with code.

VB.net, oh how I hate thee, let me count the ways...

WARNING: Rant ahead

I try not to post rants on my blog, usually they serve no purpose other than to let off steam, but this one has irked me for so long. Those of you who read my blog know that I post all of my code in C#. Which, for better or worse, is my language of choice. What you may not know is that I have to write a lot of VB.net for my day job. I do not relish this fact, but it does allow me to appreciate C# that much more.

I also know that all CLR languages are pretty much created equal. Anything I can do in C# I can do in VB.net(almost), and a few things you can actually do easier. This is not what irks me about VB.net though, it has nothing to do with its power (okay, a little bit) and everything to do with its syntax. So what is it about VB.net that just makes my skin crawl?

It is the fact that this statement makes no sense?

Dim values() As String

What does that do? Well, it creates an array. It would probably be more apparent if we wrote it like this (and yes, both are valid, sigh...):

Dim values As String()

Nope! Not really, it just looks like we forgot to put a "new" in there.

So, if we add a length, it is a bit easier to tell what we are doing, but not really:

Dim values(5) As String

So, that means we can also do this...right?

Dim values As String(5)

Nope! As VB.net tells me "Array bounds are not valid in type specifiers". Hmm. So what happens if I declare an array and want to specify its size later? Can I do this?

Dim values As String()
values = New String(5)

No, of course you can't! How is the compiler supposed to know that I am not trying to declare an String object in an array variable? You have to do this:

Dim values As String()
values = New String(5) {}

Ugh. Pretty ugly. You declare arrays of higher rank like this:

Dim values(5, 5, 5) As String

It looks like I am calling a freakin' method. So, if VB.net uses parentheses for array bounds, does it also use them to access indexed properties? Yep, why not? Everything else uses them. So, check this out...

Dim values As New ArrayList()
values.Add(New Object)
Dim result As String = values(0).ToString()

That is so ugly it makes you want to slap your momma. And what is up with the "New Object"? Well, I forgot to tell you that the parentheses for object construction is OPTIONAL. Yep, you heard me, optional. Jeebus. And then you see the "values(0).ToString()" it is a veritable party of parentheses. But what happens if we want a generic list?

Dim values As New List(Of String)()
values.Add(New String(New Char() {"I"c}))
Dim result As String = values(0).ToString()

Oh my. Yep, you aren't seeing double. That crazy "(Of String)" crap is how you pass generic parameters (and you declare them this way as well!). Then the parentheses after that is for the constructor, but wait, those are optional. So then we are calling Add and passing in a new String which we are initializing with an array of characters. Oh, and that little "c" on the end of "I", yeah, that is how you declare a static character in VB.net. Since they couldn't go the C# route and use ' for characters and " for strings, or even easier go the Pascal route and just make single character strings convertible to characters! Someone think of the children!

I know what you are saying "Hold on, up to this point you have shown me that parentheses are used for arrays, indexed properties, generic parameter passing, generic parameter declaration, and method calls! But they are optional for empty constructors? That is crazy." Yes, yes it is. But what I didn't tell you is that they are also optional for parameterless method calls, but if you put them on a property they are legal! So, this piece of code is completely valid:

Dim value As New MyObject
value.Property() = "value"
value.MethodCall

So, am I setting a method here? Why isn't the compiler complaining about an unassigned statement? Because this crap is allowed. And if we do this:

Dim value As String = value.Property()

You can't even tell if we are calling a method or a property.

You think I am done? Well, you haven't stepped into the convoluted world of VB.net casting. VB.net casting operators look like methods, take this for instance:

Dim value1 As Object = "value"
Dim value2 As String = CType(value, String)
Dim value3 As String = DirectCast(value, String)
Dim value4 As String = CStr(value)

Ummmmmm. WTF? Seriously. All three lines *essentially* do the same thing. "CType" is like the C# "as" keyword and "DirectCast" is like C#'s "(String)value" cast. The real cluster comes from the fourth line. There are a bunch of these shortened methods for doing casts like CDec, CStr, CObj, CInt, CULng, etc... Seriously? So VB.net spells out EVERYTHING except for these freakin' special case casting methods. Geez.

Oh, and that is not all. How about VB.net's ridiculous boolean operators. I'm sorry, but what is wrong with this statement?

If value1 Is Nothing And value1.Id > 0 Then

Besides the fact that it is insanely verbose compared to:

if (value1 != null && value1.Id > 0)

And besides the fact that you can't use "=" for doing a boolean check on "Nothing" (which is VB.net's equivalent of null). The problem with that statement is that you will get an exception if value1 is null! And why is that? Well, because "And" is not a short circuit boolean operator! The runtime will happily try to evaluate "value1.Id > 0" even if value1 is null. Instead you must use "AndAlso" or "OrElse" in order to get short circuit evaluation.

If value1 Is Nothing AndAlso value1.Id > 0 Then

So, now that we have covered some of the ridiculous crap, what about the missing stuff?

Where is my ternary operator?

bool isOn = false;
string value = isOn ? "Yep" : "Nope";

Where is my null coalescing operator?

string possibleValue = null;
string value = possibleValue ?? "nothing";

Where is my multi-line lambda?

List<string> values = new List<string>();
var values2 = values.Select(v => { if (v != null) 
                        { return v; } 
                    else 
                        { return "nothing"; } });

Where are my incrementing and decrementing operators??

int i = 1;
i++;
i--;

Where are my multi-line comments?

/*
 This is really ugly
 in Vb.net
*/

And finally where are my automatic properties? (A new feature in C# 3.0)

public int Value{ get; set; }

Wow, that went on a lot further than I expected. I guess I had more repressed emotions than I thought. Argh. Seriously though, I know that most of my complaints about VB.net are because of previous baggage that it has carried over from the past, but for me that doesn't make it any easier. I also don't carry any of the stigmas that most people do about VB.net programmers, I'm sure there are one or two good ones out there. :-) Well, that is all for this evening, goodnight folks.