How Do Valuetypes Derive from Object (Referencetype) and Still Be Valuetypes

How do ValueTypes derive from Object (ReferenceType) and still be ValueTypes?


C# doesn't allow structs to derive from classes

Your statement is incorrect, hence your confusion. C# does allow structs to derive from classes. All structs derive from the same class, System.ValueType, which derives from System.Object. And all enums derive from System.Enum.

UPDATE: There has been some confusion in some (now deleted) comments, which warrants clarification. I'll ask some additional questions:

Do structs derive from a base type?

Plainly yes. We can see this by reading the first page of the specification:

All C# types, including primitive types such as int and double, inherit from a single root object type.

Now, I note that the specification overstates the case here. Pointer types do not derive from object, and the derivation relationship for interface types and type parameter types is more complex than this sketch indicates. However, plainly it is the case that all struct types derive from a base type.

Are there other ways that we know that struct types derive from a base type?

Sure. A struct type can override ToString. What is it overriding, if not a virtual method of its base type? Therefore it must have a base type. That base type is a class.

May I derive a user-defined struct from a class of my choice?

Plainly no. This does not imply that structs do not derive from a class. Structs derive from a class, and thereby inherit the heritable members of that class. In fact, structs are required to derive from a specific class: Enums are required to derive from Enum, structs are required to derive from ValueType. Because these are required, the C# language forbids you from stating the derivation relationship in code.

Why forbid it?

When a relationship is required, the language designer has options: (1) require the user to type the required incantation, (2) make it optional, or (3) forbid it. Each has pros and cons, and the C# language designers have chosen differently depending on the specific details of each.

For example, const fields are required to be static, but it is forbidden to say that they are because doing so is first, pointless verbiage, and second, implies that there are non-static const fields. But overloaded operators are required to be marked as static, even though the developer has no choice; it is too easy for developers to believe that an operator overload is an instance method otherwise. This overrides the concern that a user may come to believe that the "static" implies that, say "virtual" is also a possibility.

In this case, requiring a user to say that their struct derives from ValueType seems like mere excess verbiage, and it implies that the struct could derive from another type. To eliminate both these problems, C# makes it illegal to state in the code that a struct derives from a base type, though plainly it does.

Similarly all delegate types derive from MulticastDelegate, but C# requires you to not say that.

So, now we have established that all structs in C# derive from a class.

What is the relationship between inheritance and derivation from a class?

Many people are confused by the inheritance relationship in C#. The inheritance relationship is quite straightforward: if a struct, class or delegate type D derives from a class type B then the heritable members of B are also members of D. It's as simple as that.

What does it mean with regards to inheritance when we say that a struct derives from ValueType? Simply that all the heritable members of ValueType are also members of the struct. This is how structs obtain their implementation of ToString, for example; it is inherited from the base class of the struct.

All heritable members? Surely not. Are private members heritable?

Yes. All private members of a base class are also members of the derived type. It is illegal to call those members by name of course if the call site is not in the accessibility domain of the member. Just because you have a member does not mean you can use it!

We now continue with the original answer:


How does the CLR handle this?

Extremely well. :-)

What makes a value type a value type is that its instances are copied by value. What makes a reference type a reference type is that its instances are copied by reference. You seem to have some belief that the inheritance relationship between value types and reference types is somehow special and unusual, but I don't understand what that belief is. Inheritance has nothing to do with how things are copied.

Look at it this way. Suppose I told you the following facts:

  • There are two kinds of boxes, red
    boxes and blue boxes.

  • Every red box is empty.

  • There are three special blue boxes called O, V and E.

  • O is not inside any box.

  • V is inside O.

  • E is inside V.

  • No other blue box is inside V.

  • No blue box is inside E.

  • Every red box is in either V or E.

  • Every blue box other than O is itself inside a blue box.

The blue boxes are reference types, the red boxes are value types, O is System.Object, V is System.ValueType, E is System.Enum, and the "inside" relationship is "derives from".

That's a perfectly consistent and straightforward set of rules which you could easily implement yourself, if you had a lot of cardboard and a lot of patience. Whether a box is red or blue has nothing to do with what it's inside; in the real world it is perfectly possible to put a red box inside a blue box. In the CLR, it is perfectly legal to make a value type that inherits from a reference type, so long as it is either System.ValueType or System.Enum.

So let's rephrase your question:

How do ValueTypes derive from Object (ReferenceType) and still be ValueTypes?

as

How is it possible that every red box (value types) is inside (derives from) box O (System.Object), which is a blue box (a reference Type) and still be a red box (a value type)?

When you phrase it like that, I hope it's obvious. There's nothing stopping you from putting a red box inside box V, which is inside box O, which is blue. Why would there be?


AN ADDITIONAL UPDATE:

Joan's original question was about how it is possible that a value type derives from a reference type. My original answer did not really explain any of the mechanisms that the CLR uses to account for the fact that we have a derivation relationship between two things that have completely different representations -- namely, whether the referred-to data has an object header, a sync block, whether it owns its own storage for the purposes of garbage collection, and so on. These mechanisms are complicated, too complicated to explain in one answer. The rules of the CLR type system are quite a bit more complex than the somewhat simplified flavour of it that we see in C#, where there is not a strong distinction made between the boxed and unboxed versions of a type, for example. The introduction of generics also caused a great deal of additional complexity to be added to the CLR. Consult the CLI specification for details, paying particular attention to the rules for boxing and constrained virtual calls.

How / Why possible a value type derives from a reference type?

The following is the key paragraph in the documentation

Although ValueType is the implicit base class for value types, you
cannot create a class that inherits from ValueType directly. Instead,
individual compilers provide a language keyword or construct (such as
struct in C# and Structure…End Structure in Visual Basic) to support
the creation of value types.

The inheritance occurs when the compiler compiles the overriden virtual methods of System.Object. The System.ValueType class simply provides more appropriate overloads of ToString(), GetHashCode() etc. As the document states the compiler uses these overloads if the struct keyword is used (in C#). This tells the compiler use the System.ValueType methods instead of the System.Object methods.

Value Type, Reference Type and Boxing


is it accurate to say that a value type such as int is also a reference type?
…Or is it more accurate to say that a value type can be a reference type through the process of boxing.

Neither is accurate. int is a value type, period. It is not "also a reference type". And when boxed, it's not magically changed to be a reference type. The System.Object that contains it is a reference type, but inside is still the value of the value type int.

Is i holding the value of 10, or is it an object holding a reference to the value of 10?

See above. i has the type int, which is a value type, and so the variable contains the value you've assigned to it, 10.

See also What is the difference between a reference type and value type in c#?

Since Int32 is a value type why does it inherit .ToString()?

Int32 is a struct and therefore a value type.
But:

System.Object
System.ValueType
System.Int32

Int32 derives from System.ValueType and this itself derives from System.Object. Et voilà...

Is a struct just a class that derives from ValueType?

Not quite "just syntactical sugar". From the MSDN:

Although ValueType is the implicit base class for value types, you
cannot create a class that inherits from ValueType directly. Instead,
individual compilers provide a language keyword or construct (such as
struct in C# and Structure…End Structure in Visual Basic) to support
the creation of value types.

So could you say that a struct is just a class that inherits from System.ValueType semantically? That'd debatable. All struct are derived from System.ValueType, but you can't explicitly create a class that derives from System.ValueType.

In addition, of course, just being derived from System.ValueType, struct has a lot of differences from class as you probably know. But if not, I have a blog post on some of the key differences here, including but not limited to:

  • Value types are, of course, passed and assigned by value, not by reference.
  • A struct cannot accept initialization values for their fields in the definition (they always given values for their declared field types).
  • A struct can have events, but since they are value types must take care that you aren't subscribing to a copy!
  • You cannot inherit from a struct.
  • You cannot create struct parameterless constructor, struct provides one which cannot be overridden.
  • Creating an overloaded struct constructor does not hide the parameterless constructor.
  • The this keyword, used in a struct is a value variable, not a reference.
  • You do not need to use new to create an instance of a struct (but if you do this you must provide a value for all fields before it is used.

MSDN also has some good advice on when to use struct vs class. Because they are value types, you should think of them as such and limit them to smaller things (16 bytes or less) and preferably as immutable representations of a single value (like DateTime, TimeStamp etc.).

Is object a reference type or value type?

It is a reference type

Doing an example with string isn't very illuminating, because string is also a reference type (as is SampleClass, obviously); your example contains zero "boxing".

if object is reference type then why obj2 value is still "OldString"

Why wouldn't it be? When you create a new string, that doesn't change old references to point at the new string. Consider:

 object obj1 = "OldString";
// create a new string; assign obj1 the reference to that new string "OldString"

object obj2 = obj1;
// copy the reference from obj1 and assign into obj2; obj2 now refers to
// the same string instance

obj1 = "NewString";
// create a new string and assign that new reference to obj1; note we haven't
// changed obj2 - that still points to the original string, "OldString"


Related Topics



Leave a reply



Submit