Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>The reason value types can't support inheritance is because of arrays.</p> <p>The problem is that, for performance and GC reasons, arrays of value types are stored "inline". For example, given <code>new FooType[10] {...}</code>, if <code>FooType</code> is a reference type, 11 objects will be created on the managed heap (one for the array, and 10 for each type instance). If <code>FooType</code> is instead a value type, only one instance will be created on the managed heap -- for the array itself (as each array value will be stored "inline" with the array).</p> <p>Now, suppose we had inheritance with value types. When combined with the above "inline storage" behavior of arrays, Bad Things happen, as can be seen <a href="https://isocpp.org/wiki/faq/proper-inheritance#array-derived-vs-base" rel="noreferrer">in C++</a>.</p> <p>Consider this pseudo-C# code:</p> <pre><code>struct Base { public int A; } struct Derived : Base { public int B; } void Square(Base[] values) { for (int i = 0; i &lt; values.Length; ++i) values [i].A *= 2; } Derived[] v = new Derived[2]; Square (v); </code></pre> <p>By normal conversion rules, a <code>Derived[]</code> is convertible to a <code>Base[]</code> (for better or worse), so if you s/struct/class/g for the above example, it'll compile and run as expected, with no problems. But if <code>Base</code> and <code>Derived</code> are value types, and arrays store values inline, then we have a problem.</p> <p>We have a problem because <code>Square()</code> doesn't know anything about <code>Derived</code>, it'll use only pointer arithmetic to access each element of the array, incrementing by a constant amount (<code>sizeof(A)</code>). The assembly would be vaguely like:</p> <pre><code>for (int i = 0; i &lt; values.Length; ++i) { A* value = (A*) (((char*) values) + i * sizeof(A)); value-&gt;A *= 2; } </code></pre> <p>(Yes, that's abominable assembly, but the point is that we'll increment through the array at known compile-time constants, without any knowledge that a derived type is being used.)</p> <p>So, if this actually happened, we'd have memory corruption issues. Specifically, within <code>Square()</code>, <code>values[1].A*=2</code> would <i>actually</i> be modifying <code>values[0].B</code>!</p> <p>Try to debug <em>THAT</em>!</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload