2

When speaking about casting here, I mean implicit cast. Assume class B inherits from A. Because we have only single inheritance in C#, when casting reference to B to reference to A, we don't have to do any ,,this'' pointer adjustment or so. In fact, such cast is no op, because B is A, all fields of A have same offset in A object and B object.

And there comes the question: is casting reference to B to reference to some interface which B implements involves any overhead? Personally, I do not see any reason that it should, cause interfaces can't have fields (and therefore ,,this'' pointer does not have to be adjusted as in the case above). Nevertheless sometimes I can hear such opinions, hence this question.

konrad.kruczynski
  • 46,413
  • 6
  • 36
  • 47
  • Another, more pressing question is why it should matter. –  May 03 '11 at 20:06
  • 1
    I'm just curious how compiler/JIT does this from the technical point of view. Of course IL or jitted assembly can be viewed - so far I did not found any differences. However I'm not sure whether some optimizations wasn't applied. – konrad.kruczynski May 03 '11 at 20:10

1 Answers1

2

There are two costs:

  • The cost of copying a reference to another location. This is obviously minimal :)
  • The potential cost of performing genuinely virtual method calls which could otherwise be non-virtual.

For the latter, I'm talking about JIT optimizations. Consider this code:

string x = "hello";
object o = x;
string y = o.ToString();

I suspect the JIT ends up with a genuinely virtual method call, with a vtable lookup etc. No chance of inlining.

If we were to call x.ToString() instead though, I'd expect the JIT to notice that String is a final class, and so the implementation of String.ToString can't possibly be overridden any further - allowing for a call without a vtable lookup, and possibly inlining too.

This is speculation, but it's the kind of thing that's worth thinking about. The cost of treating an object as a more general type is much more likely to be significant than the cost of copying the reference.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks. This is however related rather to the cost of call via superclass or call via implemented interface. As I understood, casting itself makes no overhead (not counting reference copying). – konrad.kruczynski May 03 '11 at 20:15
  • @Jon Skeet: another related question is that if I implement IEquatable, I can gain some performance compared to override Equals only, because comparison with value types won't require boxing. Is there any gain in case of reference types? – konrad.kruczynski May 03 '11 at 20:27
  • @konrad: If you implement `IEquatable` that is. For reference types, it means you avoid the cost of the execution-time check of a cast. – Jon Skeet May 03 '11 at 20:38
  • @Jon: but isn't that cast to Object? If it is, why it has to be checked in runtime? It is always legal and after that call to Equals via vpointer is made, isn't it? – konrad.kruczynski May 03 '11 at 20:49
  • @konrad: No, in a normal non-generic `IEquatable` implementation you always end up casting *within the implementation*. Sure, making the method call is cheap - but you've got to perform the type check inside it, whereas with generics that check is unnecessary. – Jon Skeet May 03 '11 at 20:59
  • @Jon: Of course, *this* is the cast you were talking about! Now that's clear, thank you again. – konrad.kruczynski May 03 '11 at 21:14
  • @konrad.kruczynski: I would advice against having any inheritable types implement any IEquatable interfaces. Otherwise, it's very easy to end up in a situation where a type defines several versions of IEquatable which do not behave identically. BTW, if I had my druthers, there would be an interface INotEquatable, with no members, which if defined would instruct methods like Equatable.Default to ignore any IEquatable definition it might find. That would allow an immutable class to be inheritable without risking breaking immutability of any base-class behaviors. – supercat May 12 '11 at 17:01