On the Risks of Labeling - "Premature Optimization"
This post really got me. The writer describes a system design conversation, when one of the arguments is that inheritance in .NET is a possible cause of performance degradation. The author then continues to test this "degradation" using the following setup (deduced from the original post):
class Animal {
private int _legs;
public virtual int Legs { get { return _legs; }
}
class Dog : Animal { }
...
foreach (Animal a in animals) {
int i = a.Legs;
}
foreach (Dog d in dogs) {
int i = d.Legs;
}
He then thoughtfully concludes that inheritance has no performance impact, in view of his measurements.
Let's just ignore all the issues concerning the actual value of this kind of measurement, and try to focus on the original statement. Why would accessing a property on an object be affected by the inheritance chain of the object's type?
To really understand this kind of thing, you need to have virtual method dispatch memorized by heart. It's not rocket science really, but few developers (especially .NET developers) are aware of it. Consider the JITted code generation for accessing a property on the Animal object as opposed to accessing it on a Dog object, in this simplified scenario:
Animal a1 = new Dog();
int i = a1.Legs;
Animal a2 = new Animal();
i = a2.Legs;
...
0000001f mov rax,qword ptr [rbx]
00000022 mov rcx,rbx
00000025 call qword ptr [rax+60h]
...
00000042 mov rax,qword ptr [rbx]
00000045 mov rcx,rbx
00000048 call qword ptr [rax+60h]
(Note that this is 64-bit assembly language; it's not essentially different from 32-bit, so I didn't bother forcing a 32-bit environment.)
I've snipped everything irrelevant to the discussion. Note how absolutely identical the code is for both properties. If you have the theory behind you, it's also absolutely obvious why this is so - the method table entry for the Legs property will always be at the same offset for any derived type of Animal. You can continue the derivation hierarchy forever; it will still be the same code to access the property, and the same slot in the method table.
What if the property discussed in the original post was not virtual? I considered leaving this as an exercise for the reader... But here goes. Accesing a non-virtual property as trivial as this one is obviously going to be inlined. The property's backing field is stored in the Animal class part; if we have a Dog object, it must be at the same offset. Here's the relevant code generation:
...
0000001f cmp byte ptr [rbx],0
00000022 mov eax,dword ptr [rbx+8]
...
0000003f cmp byte ptr [rbx],0
00000042 mov eax,dword ptr [rbx+8]
Surprised? By now you really shouldn't be. The property is stored at the very same offset in both cases, and therefore the inlined code to access it is absolutely identical. (Theoretical side note: the first instruction in each pair merely enforces a null reference check, to ensure that we are not calling a method or accessing a property on a null reference. Note that we don't have to do anything with the result of the comparison - it's the very fact that we dereference the reference, as in [rbx], which would cause an access violation, which would be trapped by the CLR and converted to a NullReferenceException.)
So what can we conclude from this brief analysis? That comparing a piece of code to an absolutely identical piece of code will yield identical performance for both pieces of code. Stunning, really.