Why does C# always use callvirt?


This question came up on an internal C# alias, and I thought the answer would be of general interest. That’s assuming that the answer is correct – it’s been quite a while.


The .NET IL language provides both a call and callvirt instruction, with the callvirt being used to call virtual functions. But if you look through the code that C# generates, you will see that it generates a “callvirt” even in cases where there is no virtual function involved. Why does it do that?


I went back through the language design notes that I have, and they state quite clearly that we decided to use callvirt on 12/13/1999. Unfortunately, they don’t capture our rationale for doing that, so I’m going to have to go from my memory.


We had gotten a report from somebody (likely one of the .NET groups using C# (thought it wasn’t yet named C# at that time)) who had written code that called a method on a null pointer, but they didn’t get an exception because the method didn’t access any fields (ie “this” was null, but nothing in the method used it). That method then called another method which did use the this point and threw an exception, and a bit of head-scratching ensued. After they figured it out, they sent us a note about it.


We thought that being able to call a method on a null instance was a bit weird. Peter Golde did some testing to see what the perf impact was of always using callvirt, and it was small enough that we decided to make the change.

Comments (15)

  1. Interesting, kinda a fail-fast for null references.

    Do you recall why the thought was that being able to call a method on a reference that doesn’t access "this" and not failing is a bad thing?  This happens in C++ and I’ve never heard that it’s a issue.

  2. Matthew says:

    Doesn’t this also help in the case where a method in version 1 of a library is not virtual, but it is decided that it should be made virtual in version 2?  If the C# compiler built a program against version 1 it will always called the method non-virtually, even if the library was updated to version 2.  Going from non-virtual to virtual would have to be considered a breaking change in this case. (Or is it still a breaking change?)

    And the C# compiler doesn’t use "callvirt" for struct methods.  (And obviously it doesn’t for calls to static methods and calls through the "base" reference).

    Oh, and with the new Extension methods, you can simulate instance methods that accept a null "this" parameter. I’ve come across places where this can be useful, but I usually chicken out because it may end up being confusing in the long run.

  3. ericgu says:

    Peter,

    We thought it was a bad idea because some smart guys got confused by the behavior, and there really isn’t any reason to support the behavior.

    Matthew,

    I don’t think that’s really a benefit – it wouldn’t be true in all other languages, so it would still be a breaking change.

  4. Eric,

    Does this mean if we mark all our methods as virtual, there will be little performance impact?

  5. ShayEr says:

    Eric, Please read (The Old New Thing) => (http://blogs.msdn.com/oldnewthing/archive/2007/08/16/4407029.aspx).

    Isn’t cmp [ecx], ecx solves the problem already?

  6. Sankar Nemani says:

    I was wondering why c# supported static binding at all and didn’t make everything virtual by default like jaba even in the language. I read Anders H’s comments on that and he pointed out performance and version compatibility as two of the advantages of making non-virtual the default. What I am reading now sounds like those comments weren’t correct. Am I missing something?

  7. Sankar Nemani says:

    I get it now. So callvirt doesn’t necessarily mean that methods that are not virtual will start behaving like virtual methods. Is that right?

  8. RichB says:

    I’ve read the story about callvirt somewhere before – but I can’t remember where. The closest I can find is this from Richard Blewett:

    http://discuss.develop.com/archives/wa.exe?A2=ind0410A&L=ADVANCED-DOTNET&P=R1907&I=-3

  9. Skeup says:

    The call opcode should test the this pointer when a instance method is called.. But i gess it would be a breaking change now.

    The msdn entry about the call opcode states that the this reference should not be null, but it’s useless if it’s not enforced.

    Perhaps the next version of the clr should containe à new opcode for that.

  10. Eric,

    I understand the rationale, but you cannot imagine how many times (mostly dealing with web UI using a view engine and an IOC framework) I wished that calling a method on a null pointer wouldn’t raise an exception in c# (or that at last there could be an easy syntax to teach runtime _and_ compiler not to bother about that).

    I truly dread the appearence of the "System.NullReferenceException: Object reference not set to an instance of an object." text on my web pages 🙂

    Wouldn’t be nice that instead of writing:

    object a = null;

    if (a != null)

    {

       object b = a.ToString();

       if (b != null)

       {

           object label = b.ToString();

       }

    }

    we could write something like:

    label = CNRNR a.ToString().ToString();

    where CNRNR means "Calls on Null Return Null and don’t throw the [abovementioned] dreaded exception, Recursively", and I don’t really care about the real syntax as long as I get that? Once we are there, if there would be a nice way to make it return string.empty if label is a string, that would be perfect 😉

  11. Well, you do support it and you don’t support it.

    Extension methods support a null "this".  So, in that respect it’s inconsistent.  Yes, extension methods compile to a direct static method call and can’t be checked a runtime; but from a source-code view you’ve got two ways of working…

    I certainly don’t think it’s important enough to change at this point.

  12. int19h says:

    > Do you recall why the thought was that being able to call a method on a reference that doesn’t access "this" and not failing is a bad thing?  This happens in C++ and I’ve never heard that it’s a issue.

    Actually, it is undefined behavior to access any non-static member (including methods) via a null pointer in C++, and the compiler is free to insert a check. If any C++ code relies on this behavior, it’s not conformant (there are a few such places in MFC source).

  13. TradeOptimizer says:

    Actually, if I recall properly Delphi allows calls on null pointers and I’ve had many uses for them in being able to simulate static function inheritance.

    Not sure if delphi was building a VTable in those cases but it sure was a nice feature.

    I’ve come to places so far where trying to do similar things in C# was messy. Like if you have a class which needs a static property, and would like to force an implementation in derived instances, you could do abstract in Delphi. Then again, on our classes in C#, we got to remember to implement it all the time.

    Anyways, I wish it would had been there, or as an option to allow it.

  14. Rick Byers says:

    Method calls using the C# ‘ base ’ keyword get compiled to an IL ‘ call ’ instruction, rather than the