Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why don't structs support inheritance?

People also ask

Does struct support inheritance?

Structs cannot have inheritance, so have only one type. If you point two variables at the same struct, they have their own independent copy of the data. With objects, they both point at the same variable.

Why structs Cannot inherit from another struct?

Because it is the way structs are represented in . NET. They are value types and value types don't have a method table pointer allowing inheritance.

Does structure support inheritance in C#?

A structure type can't inherit from other class or structure type and it can't be the base of a class. However, a structure type can implement interfaces.

Can structs have inheritance C++?

C++ Classes/Structures Inheritance Classes/structs can have inheritance relations. If a class/struct B inherits from a class/struct A , this means that B has as a parent A . We say that B is a derived class/struct from A , and A is the base class/struct.


The reason value types can't support inheritance is because of arrays.

The problem is that, for performance and GC reasons, arrays of value types are stored "inline". For example, given new FooType[10] {...}, if FooType is a reference type, 11 objects will be created on the managed heap (one for the array, and 10 for each type instance). If FooType 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).

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 in C++.

Consider this pseudo-C# code:

struct Base
{
    public int A;
}

struct Derived : Base
{
    public int B;
}

void Square(Base[] values)
{
  for (int i = 0; i < values.Length; ++i)
      values [i].A *= 2;
}

Derived[] v = new Derived[2];
Square (v);

By normal conversion rules, a Derived[] is convertible to a Base[] (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 Base and Derived are value types, and arrays store values inline, then we have a problem.

We have a problem because Square() doesn't know anything about Derived, it'll use only pointer arithmetic to access each element of the array, incrementing by a constant amount (sizeof(A)). The assembly would be vaguely like:

for (int i = 0; i < values.Length; ++i)
{
    A* value = (A*) (((char*) values) + i * sizeof(A));
    value->A *= 2;
}

(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.)

So, if this actually happened, we'd have memory corruption issues. Specifically, within Square(), values[1].A*=2 would actually be modifying values[0].B!

Try to debug THAT!


Imagine structs supported inheritance. Then declaring:

BaseStruct a;
InheritedStruct b; //inherits from BaseStruct, added fields, etc.

a = b; //?? expand size during assignment?

would mean struct variables don't have fixed size, and that is why we have reference types.

Even better, consider this:

BaseStruct[] baseArray = new BaseStruct[1000];

baseArray[500] = new InheritedStruct(); //?? morph/resize the array?

Structs do not use references (unless they are boxed, but you should try to avoid that) thus polymorphism isn't meaningful since there is no indirection via a reference pointer. Objects normally live on the heap and are referenced via reference pointers, but structs are allocated on the stack (unless they are boxed) or are allocated "inside" the memory occupied by a reference type on the heap.


Class like inheritance is not possible, as a struct is laid directly on the stack. An inheriting struct would be bigger then it parent, but the JIT doesn't know so, and tries to put too much on too less space. Sounds a little unclear, let's write a example:

struct A {
    int property;
} // sizeof A == sizeof int

struct B : A {
    int childproperty;
} // sizeof B == sizeof int * 2

If this would be possible, it would crash on the following snippet:

void DoSomething(A arg){};

...

B b;
DoSomething(b);

Space is allocated for the sizeof A, not for the sizeof B.


Here's what the docs say:

Structs are particularly useful for small data structures that have value semantics. Complex numbers, points in a coordinate system, or key-value pairs in a dictionary are all good examples of structs. Key to these data structures is that they have few data members, that they do not require use of inheritance or referential identity, and that they can be conveniently implemented using value semantics where assignment copies the value instead of the reference.

Basically, they're supposed to hold simple data and therefore do not have "extra features" such as inheritance. It would probably be technically possible for them to support some limited kind of inheritance (not polymorphism, due to them being on the stack), but I believe it is also a design choice to not support inheritance (as many other things in the .NET languages are.)

On the other hand, I agree with the benefits of inheritance, and I think we all have hit the point where we want our struct to inherit from another, and realize that it's not possible. But at that point, the data structure is probably so advanced that it should be a class anyway.