Dot Net Thoughts

October 12, 2007

Why Language is Important (Why I prefer C#)

Filed under: Debugging,Misc Thoughts — dotnetthoughts @ 7:13 pm
Tags: , , , , , , ,

How many times have you heard this statement?

 “It doesn’t really matter whether you choose Visual Basic.Net or C#. It all compiles down to the CLR, anyway.”

This statement makes me shudder. It’s at least partially true. All managed code does compile down into the common language runtime. This is what allows us to mix and match components written in different languages when building an application. What this statement doesn’t recognize is the fact that every language was created for a specific purpose.

In his book CLR via C#, Jeffrey Richter lists around two dozen different compilers he knows of. These include many well known languages such as C#, J#, LISP, Perl, and Eiffel, just to name a few. Having this many different compilers would be a lot of wasted effort if each language acted exactly the same as every other language out there.

The reality is that each language has its advantages and disadvantages. C# and VB.Net are great for handling Input and Output. APL is optimized for mathematics and finance. PERL is a monster when it comes to string manipulation. LISP, one of the oldest programming languages, is still the language of choice for AI. C++.Net allows both managed and unmanaged code to run within the same module. Every language is designed for a specific type of development.

I would love to learn the ins and outs of all the different languages out there. When working as a consultant, however, reality dictates that I will almost always be programming either C# or Visual Basic.Net.

Choosing between these two isn’t always an easy decision. In many ways, I find the UI presented by the Visual Basic team to be superior to the UI offered by C#. Filtering down methods and properties to those most used, the my namespace, and better on-the-fly error detection make Visual Basic.Net a very enjoyable programming experience. When I’m in the IDE, I feel that VB wins hands down.

Ultimately, though, when I look at the intent of the entire language (and not just the UI), VB loses some of its shine. The intent of the C# language was to build a clean and new language around the .Net runtime. C# has a clean mapping between .Net runtime capabilities and features. Close alignment with the framework was its intent. VB, on the other hand, was designed to maintain market share by retaining much of the language from the previous version of VB. This often did not make sense in the context of the new .Net environment.

Let me give you an example. In legacy VB days, there was no such thing as structured exception handling. All errors were handled either by calling On Error Goto <label>, or by calling On Error Resume Next. On Error Goto isn’t a particularily good way to handle errors. On Error Resume Next is a disaster. Take this code, for example:

  Sub ResumeNextTest()
     On Error Resume Next
     Dim xml As XmlDocument = New XmlDocument
     xml.Load("c:\AMissingFileName.xml")
     Console.WriteLine(xml.OuterXml)
     Console.WriteLine("ResumeNext complete.")
  End Sub

If the attempt to load the xml fails, there will be no indication. You could probably infer that the xml didn’t load when the Console prints out nothing on the next line, but there is no explicit indication. In this example, the Xml data is accessed right away. In a more complex app, though, the problem of the missing Xml data may not show up for quite some time.

The .Net runtime has no concept of On Error Resume Next, though. If an error is thrown, something has to happen. How does VB get around this?

To find out, I wrote a simple Console App with the above method included, and ran reflector against it to see what the VB compiler did when it converted the code to IL. (I’ve included the converted code at the bottom of this post.) Essentially, VB wraps the entire On Error Resume Next method in a try-catch block. As it progresses through the code, the CurrentStatement variable is updated to indicate the location in the code. Should an exception occur, the exception is swallowed, and the user is redirected to the label following the point that the trouble happened.

While this is a clever way of solving the problem, it allows a very dangerous practice that should have been eliminated to carry on. Furthermore, if I ever had a developer present me with this kind of spaghetti code during a code review, we would have to have a serious talk.

Your choice of VB, C#, or any other compiler is up to you. Be sure you know the pros and cons of whatever language before you develop with it, though.

Good luck and code safe!

 Mike

public static void ResumeNextTest() 
{ 
    // This item is obfuscated and can not be translated. 
    int VB$ResumeTarget; 
    try 
    { 
        int VB$CurrentStatement; 
    Label_0001: 
        ProjectData.ClearProjectError(); 
        int VB$ActiveHandler = -2; 
    Label_0009: 
        VB$CurrentStatement = 2; 
        XmlDocument xml = new XmlDocument(); 
    Label_0011: 
        VB$CurrentStatement = 3; 
        xml.Load(@"c:\AMissingFileName.xml"); 
        goto Label_0089; 
    Label_0024: 
        VB$ResumeTarget = 0; 
        switch ((VB$ResumeTarget + 1)) 
        { 
            case 1: 
                goto Label_0001;   

            case 2: 
                goto Label_0009;   

            case 3: 
                goto Label_0011;   

            case 4: 
                goto Label_0089;   

            default: 
                goto Label_007E; 
        } 
    Label_0044: 
        VB$ResumeTarget = VB$CurrentStatement; 
        switch (((VB$ActiveHandler > -2) ? VB$ActiveHandler : 1)) 
        { 
            case 0: 
                goto Label_007E;   

            case 1: 
                goto Label_0024; 
        } 
    } 
    catch (object obj1) when (?) 
    { 
        ProjectData.SetProjectError((Exception) obj1); 
        goto Label_0044; 
    } 
Label_007E: 
    throw ProjectData.CreateProjectError(-2146828237); 
Label_0089: 
    if (VB$ResumeTarget != 0) 
    { 
        ProjectData.ClearProjectError(); 
    } 
}

About these ads

9 Comments »

  1. Your usage of On Error Resume Next explicitely ignores errors, which creates the strawman arguement that it is problematic because errors were ignored.

    You didn’t have to ignore errors. There is a reason that it is “On Error Resume Next” instead of “On Error Ignore”

    I am not recommending that most error handling should be done in an unstructured manner. I think, however, that you arent givening On Error Resume Next the full and fair consideration it deserves.

    Comment by jkoss — October 12, 2007 @ 9:53 pm | Reply

  2. Thanks for the comment. You are correct that you can check for an error number after running some “resume next” code to see if an error occured. Using this technique raises a couple of concerns for me that I probably should have stated in my post.

    1. Unless I check the error code after every single line of code, I’m not exactly sure what line of my code causes the exception.

    2. Again, unless you’re checking after every line, the state of the method variables may have been altered from the time that the exception was generated. This can obscure the cause of the exception.

    Things like “On Error Resume Next” become another decision when choosing a language. Some teams may decide that they are comfortable with this feature in the context of a specific project or in specific situations. That’s okay as long as they understand the pros and cons of using these features, and feel that the pros outweigh the risks. Unfortunately, it’s been my experience that Resume Next is used because it is easier to use it than it is to research how to do it right. If you decide to use it with your team, you should establish very clear criteria as to exactly when it is acceptable.

    Thanks again for the comment. I appreciate it!

    MW

    Comment by dotnetthoughts — October 12, 2007 @ 10:58 pm | Reply

  3. I do not think that #1 is valid either, because it is the same situation with Try/Catch. If we dont surround each and every line with a Try/Catch block then we still wont know which line caused the error.

    #2 does seem like a valid concern in regards to On Error Resume Next.

    I am pointing this all out because back in the VB98 days, On Error Resume Next was the method of error handling that gave you the same sort of abilities that a per-line Try/Catch gives you in that you can place your error handling code immediately after the error-prone code.

    As far as #2 is concerned, On Error Goto actualy gave us better error handling ability in VB6 than multi-line Try/Catch blocks will give us in VB.NET because we can choose to

    (A) skip the offending statement (Resume Next)
    (B) fix the problem and try again (Resume)
    (C) skip the remainder of the try block (Never resume)

    Good or bad, Try/Catch only seems to give us the option of (C).

    Normally I am for more options and against less options, so I am glad that On Error made its way into VB.NET even though I can’t recall ever actualy using it. Exception handling isnt something I usualy concern myself over because my code is almost never consumed by the public…

    I have recently found a performance-critical bug in VB.NET that is in both VB2005 and VB2008 beta. You are right that these languages are different even though they both produce cil. The compilation from source -> cil is just as important as from cil -> native and the two compilers, VB.NET and C#, sometimes produce drastically different cil with what would otherwise be equivilent source code.

    Comment by jkoss — October 13, 2007 @ 10:31 pm | Reply

  4. I was thinking about your reply, and was playing around with a few things.

    The offending line number does show up in the stack trace, but I don’t know off the top of my head a quick and easy way to pull them out. I’m going to have to play with that a little bit.

    While looking at that, I ran across something interesting, though. I built a sample app, and the stack trace shows the line number of the exception for both Debug and Release builds. This really caught me off guard. There’s obviously something that I don’t quite understand about the different build types anymore.

    Looks like I have some more learning to do. If I can find the time, I hope to write up a new blog entry on debug, release, and pdb files this weekend.

    Thanks for keeping me thinking!

    MW

    Comment by dotnetthoughts — October 16, 2007 @ 7:18 pm | Reply

  5. For anyone else that may stumble upon this as I did… A quick and easy way to get the line number that caused the error:

    Try

    Catch ex As Exception
    Dim trace as New System.Diagnostics.StackTrace(ex, True)
    trace.GetFrame(0).GetMethod().Name ‘Method name
    trace.GetFrame(0).GetFileLineNumber() ‘Line Number
    End Try

    Comment by Javier — January 3, 2008 @ 7:46 am | Reply

  6. Thanks, Javier!

    I blogged a c# version of this at Where did my exception occur as well.

    Thanks for reading!

    MW

    Comment by dotnetthoughts — January 3, 2008 @ 11:09 am | Reply

  7. dude, there is a syntax in vb net like so:
    on error resume next

    so i don’t know why you wrote that particular comment.

    Comment by kourosh — August 6, 2008 @ 12:39 am | Reply

  8. Has anyone ever seen a situation where the .Net code and line numbers displayed in a stack trace do not match the actual source (and compiled) code? If so, do you know what may cause that situation? Any suggestions would be most appreciated, so thanks in advance.

    Comment by JoPett — March 16, 2010 @ 2:13 pm | Reply

  9. […] was reading the post Why Language is Important (Why I prefer C#) from ‘Dot Net Thoughts’ and the first paragraph of the article ends with this […]

    Pingback by “Every language was created for a specific purpose” | Ask Programming & Technology — November 18, 2013 @ 10:57 pm | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Rubric Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: