views:

723

answers:

8

Hi,

I know C# has both value and reference types, but how can you do a this:

int age = 100;

string blah = age.ToString();

If age is a value type, how does it have a ToString method on it? Does it get converted to an object ONLY when required internally then?

+6  A: 

System.Int32 inherits System.ValueType which inherits System.Object.

All class, struct, enum, array, nullable and delegate types eventually derive from object. All interface types and type parameter types are implicitly convertible to object. And all pointer types neither derive from nor are convertible to object

ng5000
System.Int isn't a type. You probably mean System.Int16/Int32/Int64.
Noldorin
AFAIK, primitive types do NOT derive from object, but are boxed to wrapper classes that inherit from object.
Stefan Steinegger
they are primitive types
Syed Tayyab Ali
@Stefan - maybe you're thinking of Java?
Daniel Earwicker
Ah yes, thanks for the edit.
ng5000
The primitive type generates IL for System.Int32 ("CLR via C#", Ritcher, P.117)
ng5000
It is NOT TRUE that all types derive from system.object. All class, struct, enum, array, nullable and delegate types _derive from_ object. All interface types and type parameter types are _implicitly convertible to_ object. And all pointer types neither derive from nor are convertible to object.
Eric Lippert
ng5000
Correct. When you say class C<T> { T t; } the type of field t is T, which is a _type parameter type_. When you say C<int>, the type of field t is int; int is the _type argument_ corresponding to _type parameter_ T.
Eric Lippert
+7  A: 

You want to look up boxing/unboxing.

Boxing

Russell Troywest
Nothing is boxed here.
Joel Coehoorn
Interesting. I thought the int needed to be boxed before the ToString() function could be called but I just used ildasm on the code in the question and the MSIL code does not have a box command. Looks like I need to research my own link ;)
Russell Troywest
@MrPeregrination - Check my answer below, I've learned about the boxing stuff while learning Reflection.Emit, hope it clears stuff up a bit.
kek444
+1  A: 

Comparing "Value Type" vs "Reference Type" doesn't say anything about whether the type is or is not an object. All it tells is you is the semantics of the type: things like how it's passed to functions, whether you need to use 'new' to instantiate it, and whether it's stored on the stack or the heap. Even that last one is just an implementation detail.

Joel Coehoorn
+3  A: 

All Framework objects inherit from System.Object (though it is possible to declare a type in MSIL which doesn't).

The object.ToString() method is a virtual method.

The special rule for value types which attempt to call a method from System.Object is this:

If the value type has overridden the method (as int and all numeric types do with ToString()) then the value type is not boxed ("converted" or "wrapped" to object), but the implementation method is called directly.

If the value type did not provide an implementation for such method (for example, a custom struct), the value type is boxed, and the base implemented mathod is called.

As for details about boxing/unboxing, there's plenty of information in msdn.

kek444
+2  A: 

The key difference between value types and reference types is that value types are stored on the stack but reference types are stored in the heap. (Actually, this isn't quite the correct definition, value/reference type refers to the semantics of how they behave in situations, it's easiest to think about this in terms of a local stack and a global heap, but it doesn't necessarily have to be implemented like this)

All types (reference and value) inherit from Object. (Although, like others have said it is possible to define one that doesn't, but not in C#, you have to do it in raw IL)

In order for a value type to call a method on the base Object type it must first be boxed so it can be treated as a reference type (boxing is the process of taking a value type and shoving it into a reference type shaped box so it is on the heap and behaves like a reference type). However, most of the common numeric value types like Int32 implement their own versions of ToString so they don't have to be boxed to call them.

Value types, can have methods and properties just like reference types. The limitations are that structs (C#'s value types) don't support inheritance (except from Object) or finalizers.

There is a good article on the differences here .

Simon P Stevens
+1  A: 

Perhaps more of an understanding of the OO calling convention is needed.

When an object is created, it doesn't actually copy the code for ToString, behind the scenes your object call is translated from

target.ToString ();

to something logically like:

ToString (target);

So there's only one copy of function code (per polymorphic instance) and an object pointer is passed in when a method is called.

+4  A: 

If age is a value type, how does it have a ToString method on it?

Value types are allowed to have methods on them. Why wouldn't they? A method "on a type" is just a hunk of code that happens to be associated with a particular type; why do you believe that it matters whether that type is classified as a "reference type" or "value type"?

That's not a rhetorical question. I am interested in learning about what intuitions people have about code, particularly when those intuitions are incorrect. By understanding what people get wrong intuitively, we can try to come up with better abstractions that are more intuitive.

Does it get converted to an object ONLY when required internally then?

What exactly do you mean by "converted to an object"? Do you mean "boxed"?

There are many situations in which a value type must be boxed. Some of them are straightforward -- like when you cast a value type to object or an interface. Some of them are obscure. (There are bizarre situations in generic methods where we must box and unbox things in ways you might not expect.)

In this particular situation there is no boxing. Calling a method directly implemented on a value type simply calls that hunk of code. There's no need to treat the thing as "object"; the hunk of code we're calling knows the type of the thing.

Eric Lippert
I guess the reasoning goes something like this (recklessly exposing my own ignorance by only mild exageration): when value types go in those heap/stack/registry thingies, they are put in their own box, with nothing else. But reference types get put as pointers to objects - which live somewhere else and have all their methods with them.
Benjol
A: 

all of the answers are mostly correct but i feel like the method belongs to system.object and system.valuetype and system.Int32 are derived from it .so when you create an instence of it it will show the methods of the base class .