16

Just wondering why we need struct if class can do all struct can and more? put value types in class has no side effect, I think.

EDIT: cannot see any strong reasons to use struct

A struct is similar to a class, with the following key differences:

  • A struct is a value type, whereas a class is a reference type.
  • A struct does not support inheritance (other than implicitly deriving from object).
  • A struct can have all the members a class can, except the following:
  • A parameterless constructor
  • A finalizer
  • Virtual members

A struct is used instead of a class when value type semantics are desirable. Good examples of structs are numeric types, where it is more natural for assignment to copy a value rather than a reference. Because a struct is a value type, each instance does not require instantiation of an object on the heap. This can be important when creating many instances of a type.

Chris
  • 2,959
  • 1
  • 30
  • 46
5YrsLaterDBA
  • 33,370
  • 43
  • 136
  • 210

9 Answers9

16

Custom value types aren't absolutely necessary - Java does without them, for example. However, they can still be useful.

For example, in Noda Time we're using them pretty extensively, as an efficient way of representing things like instants without the overhead of an object being involved.

I wouldn't say that "class can do all struct can and more" - they behave differently, and should be thought of differently.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    Reading up on the diff between class and struct the last few days. Pretty sure I have wrapped my mind around most (all?) of the nuances (performance in "x" situation, memory usage in "y" situation, blah , blah, blah). This is over-simplifying a bit but would you say the following statement is fairly accurate? Other than value-vs-ref types, classes are structs with additional capabilities but also extra overhead. Unless you need the extra capabilities or plan to pass as a parm (value vs ref type comes into play here), structs use less memory and "perform" better than classes. – Andrew Steitz May 09 '16 at 20:11
  • @AndrewSteitz: No, I wouldn't put it that way. The "value type vs reference type" *is* the primary difference... and depending on how they're used, you can end up using a lot less memory with reference types than value types. (Imagine a 32-byte value, where you have 100 of the same value... with a reference type you could have 100 references to the same object, vs 100 32-byte copies for the value type.) – Jon Skeet May 09 '16 at 20:42
  • Much obliged! I thought I had wrapped my mind around the differences, but your emphasis that value-vs-reference is THE primary difference tells me that I should study a little more. – Andrew Steitz May 10 '16 at 03:18
9

Why use a struct when a class works? Because sometimes a class doesn't work.

In addition to the performance reasons mentioned by Reed Copsey (short version: fewer objects that the GC needs to track, allowing the GC to do a better job), there is one place where structures must be used: P/Invoke to functions that require by-value structures or structure members.

For example, suppose you wanted to invoke the CreateProcess() function. Further suppose that you wanted to use a STARTUPINFOEX structure for the lpStartupInfo parameter to CreateProcess().

Well, what's STARTUPINFOEX? This:

typedef struct _STARTUPINFOEX {
    STARTUPINFO                    StartupInfo;
    PPROC_THREAD_ATTRIBUTE_LIST    lpAttributeList;
} STARTUPINFOEX, *LPSTARTUPINFOEX;

Notice that STARTUPINFOEX contains STARTUPINFO as its first member. STARTUPINFO is a structure.

Since classes are reference types, if we declared the corresponding C# type thus:

[StructLayout(LayoutKind.Sequential)]
class STARTUPINFO { /* ... */ }

class STARTUPINFOEX { public STARTUPINFO StartupInfo; /* ... */ }

The corresponding in-memory layout would be wrong, as STARTUPINFOEX.StartupInfo would be a pointer (4 bytes on ILP32 platforms), NOT a structure (as is required, 68 bytes in size on ILP32 platforms).

So, to support invoking arbitrary functions which accept arbitrary structures (which is what P/Invoke is all about), one of two things are necessary:

  1. Fully support value types. This allows C# to declare a value type for STARTUPINFO which will have the correct in-memory layout for marshaling (i.e. struct support, as C# has).

  2. Some alternate syntax within P/Invokeable structures which would inform the runtime marshaler that this member should be laid out as a value type instead of as a pointer.

(2) is a workable solution (and may have been used in J/Direct in Visual J++; I don't remember), but given that proper value types are more flexible, enable a number of performance optimizations not otherwise achievable, and make sensible use within P/Invoke scenarios, it's no surprise that C# supports value types.

jonp
  • 13,512
  • 5
  • 45
  • 60
3

In general, use a class.

Only use a struct when you absolutely need value type semantics.

Randolpho
  • 55,384
  • 17
  • 145
  • 179
  • 6
    Struct types do not "only live on the stack". An array of ints isn't on the stack. A class field of type int is not on the stack. A static field of type int is not on the stack. A local variable of type int that is in an iterator block is not on the stack. A local variable of type int that is a closed-over outer variable of an anonymous method or lambda expression is not on the stack... struct types are usually *not* on the stack, so saying "they can only live on the stack" is completely misleading. The value of structs is that you can put *lots of them on the heap for cheap*. – Eric Lippert Feb 19 '10 at 21:36
  • 1
    I didn't say structs only live on the stack, I said you should only *create* one when you want it to only live on the stack. Everything you said is absolutely true, but if the struct will only live while encapsulated in some other datatype, it should be a class. Only create a struct when it *must* live on the stack. – Randolpho Feb 19 '10 at 21:45
  • 1
    But there is no type, struct or otherwise, that *must* live on the stack. If what you require is something that *must live on the stack* then the language you want to be using is C, not C#. The reason to create struct types is because you want to *model something which is logically a value, not a reference*. You're conflating "lives on the stack", which is an implementation detail, with "has value semantics". Value types have value semantics no matter where they live. – Eric Lippert Feb 19 '10 at 22:05
  • @Randolpho: Eric's point is that creating a struct *doesn't* force it to live on the stack, so even if your type "must" live on the stack, it may well still not. Your answer certainly heavily implies that all structs live on the stack. – Jon Skeet Feb 19 '10 at 22:06
  • 2
    I also note that you're making the common error of "on the stack equals fast". Value types are copied by value, which means that even small ones can be more expensive to use than reference types when copied frequently; the burden of the slow, frequent copies outweighs the tiny difference in allocation and deallocation efficiency. The performance benefit of value types is not that they are *fast* but that they are *small* and *compactable*. A million boxed ints takes up way more space than a million unboxed ints. – Eric Lippert Feb 19 '10 at 22:08
  • I see your point about small and compactable. For the record, I realize that not all value types live on the stack and that stack != fast, but I realize my post is misleading. I will edit appropriately. – Randolpho Feb 19 '10 at 22:22
  • Needing a value type semantic is a (almost) necessary, but not sufficient criterion to use structs. – Stefan Jun 20 '10 at 17:31
  • @Lawnmower: what *would* be a sufficient criterion to use structs that has nothing to do with value type semantics? – Randolpho Jun 20 '10 at 17:38
  • @Randolpho that's a difficult question. Probably there is none, or at least not a single one. What I tried to say is that there are lots of situations where you "absolutely need value type semantics" but structs are the wrong choice. Reading your answer again, it doesn't imply otherwise. – Stefan Jun 20 '10 at 22:47
  • @Lawnmower: I guess I'm confused by the downvote, then. I answered the question to say that a struct should be avoided unless value type semantics are absolutely necessary. This answer is compatible with your own opinion that structs are the wrong choice. – Randolpho Jun 21 '10 at 13:44
  • 1
    @Lawnmower: How can one get value-type semantics without a struct? Given `Point p1,p2; ...; p1=p2; ...;`, how could I have a change to `p1.X` not affect `P2.X`, other than by making `Point` a struct? – supercat Jan 16 '14 at 14:34
  • @Randolpho: In addition to being appropriate when an aggregation of variables should have value semantics, structs are also appropriate in cases where an immutable reference type would work but a value type could be faster. I consider it unfortunate that Microsoft didn't recognize structure types as having two distinct usage cases, since I think such recognition could have made some aspects of .NET cleaner. – supercat Jan 16 '14 at 14:36
2

Structs are also often required for performance reasons. Arrays of structs take quite a bit less memory, and get much better cache coherency than an array of object references. This is very important if you're working with something like a rendering system, and need to generate 5 million vertices, for example.

For details, see Rico Mariani's Performance Quiz + Answers.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
2

Structs are useful simply because they are passed by value, which can actually be useful in certain algorithms. This is actually something that classes CAN'T do.

struct ArrayPointer<T>
{
    public T[] Array;
    public int Offset;
}

You can pass this structure to a method and the method can alter the value of Offset for its own needs. Meanwhile, once you return from the method, it will behave as if Offset never changed.

Robert Davis
  • 2,255
  • 2
  • 21
  • 21
  • 1
    I wouldn't favor that example, since changes to the array itself will be visible to the caller unless the called method creates a new array. A better example would be `struct Point3d {public double X,Y,Z;}`, where one wishes to know that `Point3d[100];` will always contain 100 different XYZ triplets, rather than e.g. 100 references to a common instance. – supercat Jan 16 '14 at 14:39
1
Community
  • 1
  • 1
Asad
  • 21,468
  • 17
  • 69
  • 94
0

For the average application developer, using classes is the norm. On the surface, classes make structs seem unnecessary, but when you dig deeper into the nitty-gritty details they are actually quite different.

See here for some differences between structs and classes.

The most well-known difference is that classes are reference-types and structs are value-types. This is important because it allows a library developer to control how instances of a data-type can be used.

Rouan van Dalen
  • 748
  • 4
  • 14
0

1, performance. In some cases using structures we'll get much better performance.
2, data immutability. By changing some property of a struct you'll get a new struct. This is very useful in some cases
3, better control of in memory representation. We can exactly define how the struct is located in memory and this allows us to serialize and deserialize some binary data fast and efficiently.

zihotki
  • 5,201
  • 22
  • 26
0

It is almost a must to use for interop with underlying data structure used by win32 API. I suppose a very big reason to have it in .net could be due to that reason.

Fadrian Sudaman
  • 6,405
  • 21
  • 29