tags:

views:

174

answers:

2

IL offers two statements for calling functions, i.e. call and callvirt. Call is used to call the non-virtual or static functions or any function where compiler doesn't want to do a null check on the reference.

callvirt is used to call virtual functions, non-virtual functions are also called, since compiler does a null check on the reference at run time.

Now while going through CLR via C# i found following example.

internal class SomeClass
{
   public override String ToString()
   {
      return base.ToString();
   }
}

Now ToString() is virtual function, but compiler generates the call instruction for it its ok.But the reason that Jeffrey mentioned that why callvirt is not generated because in that case the ToString() would be called recursively and will cause the StackOverFlow Exception, I tried to understand but was unable to wrap my mind around this idea ? Can anyone explain why it will cause a recursive call?

Thanks..

+1  A: 

from what I believe, a stackoverflow exception would happen if the compiler generated callvirt because:

Some code calls ToString of an object of type someclass which inherits from the class object. The ToString of *somclass" method calls the ToString Method of it's base class which is object.

If this call would be virtual, it wouldn't result in call of ToString from the class object but in a call of ToString of the actuall class (which is SomeClass).

Then you whould be in an infinitive loop, as the whole thing would start from new now.

Andre Kraemer
"If + would, you get shot by Robin Hood." - that's what my English teacher always told us... But the answer is correct ;)
AndiDog
@Andre Kraemer: Your reasoning makes sense, but you mean even an explicit call to be the base.ToString() would be interpreted as call to the SomeClass.ToString() if it was callvirt?
waheed
I was wondering how the call to base.ToString(), be treated as SomeClass.ToString(), than i came up with following explaination:The call base.ToString() is equivalent to (Object(this)).ToString(), but at runtime the type of (Object(this)) is actually SomeClass. So if callvirt is used, which determines the runtime type of the instance and calls accordingly, the function which will be called at runtime will be SomeClass.ToString() which will call itself and this will lead to an indefinite recursive call resulting in StackOverflow Exception.
waheed
+2  A: 

The explicit call to a specific super class (in this case System.Object because you wrote base) must not be callvirt because that can lead to a stack overflow.

Some C# pseudocode:

internal class SomeClass
{
   public override String ToString()
   {
       // The "return base.ToString()" call could produce one of these two possibilities:

       // This will NOT go through the class hierarchy, searching for a overwritten function
       // called ToString
       call and return System.Object::ToString()

       // But this WILL, thus calling SomeClass::ToString() recursively, so this is wrong
       // and would lead to a stack overflow
       callvirt and return System.Object::ToString()
   }
}

Hope that is what you meant.

AndiDog