Things that should be a struct (because they are values):
struct Color
struct Point
struct Rectangle
struct GLVertex
(contains location, color, normal and texcoord)
struct DateTime
Things that should be a class (because they are things to which you refer):
class RandomGenerator
class Socket
class Thread
class Window
Why?
Consider the following code.
class Button
{
public Point Location { get; set; }
}
class Program
{
public static void Main()
{
var button = Util.GetButtonFromSomewhere();
var location = button.Location;
Util.DrawText("one", location);
location.Y += 50;
Util.DrawText("two", location);
location.Y += 50;
Util.DrawText("three", location);
}
}
This will draw 3 text labels, vertically aligned. But if Point is a class, this will also move the button, which is really unexpected: var location = button.Location
feels like it should copy a value, and not a reference! In other words, we think of Point as a value type and not a reference type. "value" here is used in the mathematical sense of value. Consider the number 5, it's an abstract object "somewhere out there", you just "refer" to it. Similarly, a Point simply is. It doesn't reside anywhere, we can't change it. Therefore we choose to make it a struct, so it has the semantics users expect.
On the other hand, we could have class Button { public Window Parent { get; set; } }
. Here, Parent
is an entity, so we represent it with a reference type - Window
. It may make sense to use code like myButton.Parent.Redraw();
. So Window
should be a class.
So far so good. But all this probably sounds too vague to you. How do you really decide if something "feels" like a reference or a value? My rule of thumb is simple:
What should Foo a = b; a.Mutate();
do?
- If it seems like it should leave b unchanged, make Foo a struct.
- Otherwise make it a class.
Use the principle of least surprise here.