Discussion:
Understanding the distinction between value types and objects
(too old to reply)
Nick C
2009-10-08 15:58:53 UTC
Permalink
Hi,

I was having a discussion with some co-workers today about the
distinction between value types and objects - the discussion centred
around whether or not value types were objects. The elements adding to
our confusion were that:

* value types (which are defined as structs) inherit from the
System.ValueType class, which in turn inherits from System.Object,
which would imply that they are in fact objects
* the CLR spec isn't very clear on the matter (or at least, it wasn't
to us)

This is what I think the CLR spec says (partition 1, pages 18-20,
corresponding to pages 30-32 in the PDF at
http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-335.pdf):

* value types are not objects, because objects are 'reference type of
a self-describing value [p18]' (and value types aren't reference
types)
* boxing is used to convert a value type to an object; this is handled
completely transparently by the CLR (unlike Java for example), in that
the 'boxed type cannot be directly referred to by name [p20]' (i.e. a
developer can't create a value of the boxed type directly; the boxed
type is in effect hidden to end users)
* the types in the standard library deriving from System.ValueType
(e.g. System.Int32) describes the value type (as opposed to implying a
reference); however, any methods defined in the value type will be
applied to the object resulting from the boxing operation (i.e. boxed
reference type, as opposed to the value type), because any value type
is boxed before a method defined in its type (which derives from
System.ValueType) is called on it.

Is this correct?

This would mean that:
* value types are not objects as per the CLR at the point of
allocation, even though they inherit from System.ValueType which in
turn inherits from System.Object
* however, they are boxed to objects as soon as a method defined in
their type is called on them, which sort of explains why
System.ValueType inherits from System.Object
* a class definition doesn't necessarily imply an object (as in
System.ValueType, which is a class rather than a struct)
* to summarize, even though value types (such as structs, which
according to MSDN forbid inheritance) inherit from System.Object, they
aren't in fact objects (until they get autoboxed).

Any further clarification greatly appreciated.

Thanks,
Nick
Günter Prossliner
2009-10-08 16:22:55 UTC
Permalink
Hello Nick!
Post by Nick C
* value types (which are defined as structs) inherit from the
System.ValueType class, which in turn inherits from System.Object,
System.ValueType definies System.Object as the Base-Class.
Post by Nick C
which would imply that they are in fact objects
Language compiles are making life easy because of auto-boxing (and
unboxing), but in reality they are handled differently by the CLR.
Post by Nick C
* value types are not objects, because objects are 'reference type of
a self-describing value [p18]' (and value types aren't reference
types)
If you (or the Runtime e.g. the Garbage-Collector) has a address of an
object, it can get the type of the object(called MethodTable), because it's
contained in the "Object-Header" (beside another Int32, the SyncBlock for
other purposes). This is the "self-describing value".

Value-Type cannot exist "by their own" in the heap. They are eigher on the
stack (or in a register), or contained within another type (eigher reference
or value-type). Boxed Value-Types can exist on the heap.
Post by Nick C
* boxing is used to convert a value type to an object; this is handled
completely transparently by the CLR (unlike Java for example), in that
the 'boxed type cannot be directly referred to by name [p20]' (i.e. a
developer can't create a value of the boxed type directly; the boxed
type is in effect hidden to end users)
In the case that you don't have two different types it's transparent. The is
only System.Int32 for example, which is for the value-type and the boxed
type. The rule is simple: When a Int32 lives (directly) on the Heap it's a
boxed value-type, otherwise it's not a boxed value-type.

But the boxing and unboxing operations are not transparent for
compiler-writers or if you write IL-Code. There is an explicit box and unbox
IL-Instruction which must be used. Otherwise it's an invalid program.
Post by Nick C
* the types in the standard library deriving from System.ValueType
(e.g. System.Int32) describes the value type (as opposed to implying a
reference); however, any methods defined in the value type will be
applied to the object resulting from the boxing operation (i.e. boxed
reference type, as opposed to the value type), because any value type
is boxed before a method defined in its type (which derives from
System.ValueType) is called on it.
IIRC Calling methods on Value-Types don't cause boxing by default.
Post by Nick C
* value types are not objects as per the CLR at the point of
allocation, even though they inherit from System.ValueType which in
turn inherits from System.Object
yes
Post by Nick C
* however, they are boxed to objects as soon as a method defined in
their type is called on them, which sort of explains why
System.ValueType inherits from System.Object
IIRC not if they are not called with indirection (e.g. over an
interface-definition).
Post by Nick C
* a class definition doesn't necessarily imply an object (as in
System.ValueType, which is a class rather than a struct)
System.ValueType is a kind of special definition. You won't be able to
produce it "for your own".
Post by Nick C
* to summarize, even though value types (such as structs, which
according to MSDN forbid inheritance) inherit from System.Object, they
aren't in fact objects (until they get autoboxed).
yes



GP
Nick C
2009-10-08 17:35:31 UTC
Permalink
Thanks very much for your reply - that helps clear things up quite a
lot.
Post by Günter Prossliner
Post by Nick C
* however, they are boxed to objects as soon as a method defined in
their type is called on them, which sort of explains why
System.ValueType inherits from System.Object
IIRC not if they are not called with indirection (e.g. over an
interface-definition).
I think this is the relevant passage from the spec:

"Interfaces and inheritance are defined only on reference types. Thus,
while a value type definition (see §8.9.7)
can specify both interfaces that shall be implemented by the value
type and the class (System.ValueType or
System.Enum) from which it inherits, these apply only to boxed
values."

That seems to confirm what you mention above - value types are
autoboxed if methods defined in an interface are called on them, or if
they are inherited, but not if they are called directly on the value.
I think that this seems surprising to me because I always think of C#
as being quite similar to Java, which has a clearer distinction
between value and reference types (you can't call methods on value
types in Java; in fact, you can't define new value types.)

I guess the original debate I was having with my co-workers hinges on
the definition of an object - the CLR spec explicitly states that
objects are reference types, but the class model of Int32 suggests
that value types are also considered objects (because they inherit
from System.Object.) This seems inconsistent (just like the fact that
System.ValueType is a class but instances of it get allocated on the
stack rather than the heap), but I suppose it's just a question of
naming. If we consider objects to be something we can call methods on,
then Int32s are objects; but if we consider that all operations that
we can perform on Int32s must be done by methods, then Int32s aren't
objects (because basic arithmetic operations on Int32s aren't done via
method calls), and in that sense the CLR definition of an object seems
more consistent with the traditional definition (that all operations
on the entities should be method calls amongst others.) I guess that
in that sense C#'s object model is a sort of hybrid of pure object
orientation, because not all entities are objects.

Thanks again for your response!

Nick
Günter Prossliner
2009-10-09 09:10:11 UTC
Permalink
Hello Nick!
Post by Nick C
Thanks very much for your reply - that helps clear things up quite a
lot.
You're welcome.
Post by Nick C
That seems to confirm what you mention above - value types are
autoboxed if methods defined in an interface are called on them, or if
they are inherited
You cannot inherit from ValueTypes, only Interfaces are allowed. This is
basically based on the fact that ValueType are not self-describing, which
meens that the Runtime doesn't know the Runtime-Type of a Reference.
Post by Nick C
I think that this seems surprising to me because I always think of C#
as being quite similar to Java, ...
Such assumptions are invalid. Allthough the CLR and C# from the language
perspective have something in common with Java, comcepts are different and
things are implemented quite differently.
Post by Nick C
... which has a clearer distinction
between value and reference types (you can't call methods on value
types in Java; in fact, you can't define new value types.)
Value-Types in Java are just the "basic types" definied (like the
BuildIn-Types in .NET). For Java there may be no big deal if you can't
define Value-Types, but in .NET (e.g. with a strong P-Invoke Layer) this is
essential.
Post by Nick C
I guess the original debate I was having with my co-workers hinges on
the definition of an object - the CLR spec explicitly states that
objects are reference types, but the class model of Int32 suggests
that value types are also considered objects (because they inherit
from System.Object.)
It's definied as this in Metadata, but the CLR has "special logic" assigned
to it, like you have discovered.
Post by Nick C
This seems inconsistent (just like the fact that
System.ValueType is a class but instances of it get allocated on the
stack rather than the heap), but I suppose it's just a question of
naming.
I can't anwser why System.ValueType describes itself as a "class" in
Metadata (maybe some CLR guy from MS can kick-in). It used to have no effect
on the handling, because this Type is "hardcoded" in the CLR anyway. Maybe
because it would cause a cicular reference (System.ValueType's base-class is
System.ValueType), which maybe would be no big deal for the CLR itself, but
for Metadata-Browsing Tools (compilers, IDE's, System.Reflection, ...).
Another thing you gain from this is that the fact that System.ValueType
inherits from System.Object makes it obvious that there is something like
boxing and that you can assign a ValueType to an Object.




GP

Loading...