I’m an all-out VB enthusiast. So perhaps my answer might carry a little weight, because I actually advise against starting with it.
The optimal solution, as someone has already suggested, would be to learn both languages. This is because both languages have shaped the architecture of the .NET framework considerably. In particular, attempts to preserve compatibility to VB6 have contributed a few odd quirks to the framework.
I also find the C# syntax fundamentally flawed because it inherited the C premise of using largely nonsensical semi-colons, braces and other ASCII trash where keywords would have been more appropriate (e.g. conditional operator, lack of keyword to introduce methods and variable declarations …). You don’t need to agree with this claim/opinion; its purpose here is just to show that I’m not biased in favour of C#, quite the contrary.
That said, C# does have a much larger share of examples on the web, and support tends to be easier to get (just look at StackOverflow). VB also still encourages some bad practices if you don’t pay attention, in particular because Microsoft has irresponsibly decided to make Option Strict Off
the default setting, encouraging dangerous loose typing in some places (if you ever touch VB: never use Option Strict Off
… except for COM interop scenarios, but in future versions of VB not even there).
Another thing is that they have simply botched lambda support. Both VB and C# offer a very elegant means to express high-level structures in code using queries over data (Linq …). And both use so-called lambdas (anonymous methods, which are declared at the point of usage rather than elsewhere) to express this.
But while the C# syntax for this is concise and very readable, and tries to treat functions like first-class objects, the VB syntax is clunky and impairs readability for no good reason.1) Despite my aversion for ASCII art, keywords are actually the worse choice here.
Consider the two following code samples:
First, C#:
var items = Enumerable.Range(0, 10); // = 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
var x = items.Select(x => x * 2); // = 0, 2, 4, 6, 8, 10, 12, 14, 16, 18
var y = items.Where(Number.IsOdd); // = 1, 3, 5, 7, 9
(for a given definition of Number.IsOdd
as a static method.)
Now, consider the equivalent VB code:
Dim items = = Enumerable.Range(0, 10)
Dim x = items.Select(Function (x) x * 2)
Dim y = items.Where(AddressOf Number.IsOdd).
FAIL!
I’m sorry to say it, but everything in VB’s design of these features has gone wrong. Since they have become an integral part of .NET programming (even more so in the upcoming version), VB has now a serious disadvantage.
In conclusion, my advise is to start with C# and perhaps try to learn a bit of VB by and by, to get more perspective on .NET. By the way, the same is true for other .NET languages such as F#.
1) In fact, there are reasons for that. Alas, they are not good enough (for me). For the technically interested:
AddressOf
is required because otherwise there would be an ambiguity since parentheses are not required in VB on parameterless function calls, and method calls. However, AddressOf
is simply inadequate of we were to treat functions as first-class citizens of the language. Furthermore, the IDE automatically adds the unnecessary parentheses in all other places (except parameterless functions and constructors) already. Why not there as well? That way, the ambiguity would go away, at the cost of a trivial refactoring of legacy code (remember: every old project must be upgraded anyway, when imported in a new version of Visual Studio).
=>
cannot be used for lambdas because in VB it’s actually the same as >=
. The IDE converts the former into the latter upon typing. Of course, there are several solutions to this dilemma, ranging from finding another symbol for lambdas to just abolishing the auto-correction of =>
into >=
. I would even like a Python-like solution, resulting in almost the same code that is there today, but still being much more readable:
Dim x = items.Select(Function (x) x * 2) ' Old code '
Dim x = items.Select(Function x : x * 4) ' New code '
The colon does wonders for readability: suddenly, the function forms a flow. Or we could now use =>
instead of the colon, since it’s now unambiguous (which then would read nicely as “function where x maps to x times two”.