Structs, definitely. Why? Well, it's part feeling I guess, a vector just feels and behaves like a value.
Rico Mariani here gives some reasons why value types were chosen for certain types for an API (I don't think it's XNA he's talking about).
And while efficiency is a factor here, I don't think it's about garbage collection, but more about data density like Rico says. Say you also have a Vertex
type, that contains two Vector3
s: a Vector3
for the normal and a Vector3
for the world co-ordinates. If you made those types classes, then having an array with 100 Vertex
elements, would consist of:
- 100 * 8 bytes (8 bytes is I believe the overhead of a class in memory, 4 bytes for the type header and 4 bytes for something else, a GC handle?)
- 100 * 4 bytes (for the pointers in the array to the
Vertex
elements)
- 200 * 4 bytes (for the pointers from each
Vertex
to the two Vector3
elements)
- 200 * 8 bytes (for the 8 byte overhead that you pay for making
Vector3
a class)
- 200 * 12 bytes (for the actual payload of 3
float
per Vector3
)
6000 bytes (on a 32-bit system).
As a value type, it's simply 200 * 12 bytes = 2400 bytes. So much more efficient space-wise not to mention a lower level of indirection when reading the array.
But taking up a lot of space doesn't necessarily make it slow, using a value type incorrectly can be slower than making it a class, as I have found out. You definitely want to pass them by ref
as much as possible, avoid copying them, but this doesn't go for all operations, so measure. I think I remember calculating the dot-product was slower when passing by ref
, perhaps because it somehow prevented in-lining by making the IL larger. But don't take my word for it, just measure.