I was checking the int and float types in C# and even they have the "ToString" etc, methods meaning they are inherited from System.Object. But Doesn't this cause a performance hit? I understand that they did not make base types like int objects in java because of performance. Doesn't this rule apply to .NET as well? And if it does, then does that mean .NET is slower than Java? But practically that's not true because the programs i have made in C# run way better than those I made in Java. So is there something I don't understand here?
It's very important to understand the differences between value types and reference types. The core of the difference is what the value of an expression of the type is.
Consider:
int x = 10;
SomeClass y = new SomeClass();
Here, the value of x
really is 10 - the bits for 10 end up in the memory associated with the variable x
.
The value of y
is a reference - a way of getting to a separate object in memory.
The difference becomes very important when you use assignment, particularly with mutable reference types:
int x1 = 10;
int x2 = x1;
SomeClass y1 = new SomeClass();
SomeClass y2 = y1;
y1.SomeProperty = "Fred";
Console.WriteLine(y2.SomeProperty);
In both cases, the value of the variable is copied in the assignment - so x2
's value is 10; y2
's value is a reference to the same object. So when the object's data is modified via the property in the penultimate, you can still see that difference via y2
.
You would rarely write z1.SomeProperty = ...
when z1
is a variable of a value type, as most value types are immutable. (You can't change the value of the data itself - you have to assign a new value to the variable explicitly.) If you did, however you wouldn't see any changes via variables which were previously initialized using an assignment z1
because the value would have been copied in that assignment.
I have an article on value types and reference types which goes into all this in more detail.
Now, C# and .NET have a unified type system such that even value types inherit from System.Object
. That means you can call all the messages from Object
on value type values. Sometimes that requires boxing (converting a value type value into an Object
) and sometimes it doesn't... I won't go into all the rules right now. Importantly, if a value type overrides an object method (e.g. ToString
, or GetHashCode
) the value doesn't need to be boxed to call the method.
While boxing does have a performance penalty, it's typically overstated in my experience. These days with generics, boxing isn't really needed as much as it used to be - but so long as you only use it sensibly, it's unlikely to become a significant performance problem in your application.
EDIT: Regarding games, performance, and learning things a bit at a time...
I've seen lots of people asking questions on a relatively advanced topic without understanding the basics. There's nothing wrong with being a beginner, obviously, but in my view it's really important to learn the basics first, in a "newbie friendly" environment - which I don't think games count as.
Personally I find that console apps are the easiest way of learning most core new concepts - whether that's language features, file IO, collections, web services, threading etc. Obviously for things like "learning Windows Forms" you can't do that with a console app - but it really helps if nothing other than the Windows Forms part is new to you.
So I would strongly advise that you learn the basics of C# - things like how value types and reference types work, how parameter passing works, generics, classes, inheritance etc - before you move onto games. That may sound like extra work, but it's likely to save you time later on. When something doesn't behave as you expect it to, you'll know how the language works, so you can focus on the API behaving differently, etc. Trying to learn one thing at a time makes the whole process smoother, in my experience.
In particular, the performance requirements of games mean that sometimes it's worth writing very non-idiomatic C#. Things like preallocating objects and reusing them where you'd normally create new objects... even creating mutable structs which I'd pretty much never do in normal development. In the critical game loop, boxing or creating any objects at all may be a bad idea - but that doesn't mean these things are "expensive" in the normal frame of reference. It's really important that you understand when these things are appropriate, and when they're not... and if you start with games development, you'll get an imbalanced view of these things, IMO. You'll also potentially try to micro-optimize areas where you really don't need to - but if you have a solid grounding in C# and .NET to start with, you'll be in a better position to get everything in perspective.
As long as all objects appear to be derived from System.Object
, then for all practical purposed they are derived from System.Object
. Underneath the hood things are optimized into perfection so that an int
is just a four-byte int
most of the time but it's an object when it needs to be an object. That's what boxing is all about.
The compiler and the run-time both work very, very hard to make sure that primitive types are not overburdened with a lot of excess baggage in size or function. At the same time, all rules needed to meet the C# specification and the object hierarchy are ensured. Sometimes the compiler takes shortcuts, sometimes the run-time does the work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With