7

Say I had a very simple struct in c#

   public struct foo{
   public  int a{get;set;}
   public  int b{get;set;}
   public  int c{get;set;}
   public  int d{get;set;}
   public  string hello {get;set;}
   }

I take it the above is more 'efficient' than using a class?

At what point, if I continued to add string properties, would it be time to convert the struct to a class?

Edit: I had planned to pass this struct around a GDI - centric application. I had always assumed structs were more performant when dealing with mainly value types.

maxp
  • 24,209
  • 39
  • 123
  • 201
  • 1
    Why would it be more efficient? Trying to get what you currently know. Which it isn't in most use cases. – Dykam Feb 16 '12 at 15:48
  • Can you please justify when you say that it more efficient than using a class. Why? – Muhammad Maqsoodur Rehman Feb 16 '12 at 15:50
  • 1
    What's your definition of "efficient" in this context? – Daniel Mann Feb 16 '12 at 15:51
  • http://stackoverflow.com/a/1970340/284240 – Tim Schmelter Feb 16 '12 at 15:51
  • 2
    You should start with a class, and always use a class, in 99.99% of cases. See http://stackoverflow.com/questions/5487511/struct-vs-class – Meta-Knight Feb 16 '12 at 15:51
  • Look at http://stackoverflow.com/questions/521298/when-to-use-struct-in-c and http://stackoverflow.com/questions/521298/when-to-use-struct-in-c – Raj Ranjhan Feb 16 '12 at 15:52
  • Shouldn't this questions be in http://programmers.stackexchange.com/ ? – Muhammad Maqsoodur Rehman Feb 16 '12 at 16:08
  • [Rico Mariani's article](http://blogs.msdn.com/b/ricom/archive/2006/09/07/745085.aspx) on making use of a mutable `Point3d` struct (for GDI, etc.) is very relevant to your question. Still, I am skeptical of any `struct` that contains a `string`, especially if it is not `readonly`. – Brian Feb 16 '12 at 18:23
  • @Brian: What's the problem with strings? Given that strings are deeply immutable, they are, outside of a few corner cases, equivalent to values. I'm also unclear what making the string "readonly" would accomplish. It wouldn't make its storage location immutable. The only non-trivial immutable structs are those held within logically- or declaratively immutable storage locations, and those structs are immutable, regardless of whether they expose public fields or property setters. – supercat Feb 17 '12 at 00:48
  • @supercat: Gah, right. Structs + `readonly` is pointless. The issue I have with strings is that you're using strings in a struct, you're still dealing with indirection. For the most part, I generally only expect to see structs when dealing with small chunks of binary or numerical data. – Brian Feb 17 '12 at 01:38

5 Answers5

34

I take it the above is more 'efficient' than using a class?

Absolutely not. That is a terrible struct. Structs should be small; no more than, say, four times the size of a reference; your struct is the size of five references on an 32 bit machine. Structs should represent values; this does not appear to represent any value. Structs should be immutable; this is chock full of mutability.

At what point, if I continued to add string properties, would it be time to convert the struct to a class?

The point to convert this structure to a class was the moment you created it. It should never have been a struct in the first place. Your default assumption should be that classes are good enough; only go to a struct when you have evidence that doing so solves a problem that you actually have.

I had planned to pass this struct around a GDI - centric application. I had always assumed structs were more performant when dealing with mainly value types.

Structs are more efficient than classes in a very small number of cases: when they are small, immutable, represent values, and are composed of other values, like integers. In other cases they are less efficient: because structs are copied by value, large structs can be much slower to use than references. Because structs are copied by value, mutable structs lead to bugs because you mutate copies when you think you are mutating variables. Because structs are copied by value, they should have the semantics of values, not references. And because structs that contain only other structs can be skipped by the garbage collector entirely, structs are only more efficient for cleanup purposes when they contain no references.

In any event, the way you tell if something is more efficient is try it both ways and measure its performance against your performance goals. Use science. Set a goal and measure it. Using structs "because I assume they are more efficient" is making technical decisions on the basis of hearsay. Measure, and then you'll know what is more efficient.

Eric Lippert
  • 647,829
  • 179
  • 1,238
  • 2,067
  • Thanks for the detailed reply Eric. How do you feel about System.Drawing.Rectangle? Although this struct contains no reference types, it does contain a large number of value types. – maxp Feb 16 '12 at 16:52
  • 4
    @maxp: I would not want to make a struct much larger than that, and the fact that it is mutable is vexing. However, it arguably does behave like a value. Also, a large numbers of rectangles might be created, say, in an array, and thus they are unlikely to be copied "by themselves" a lot. A rectangle would often be passed around by passing around some reference type that contains a rectangle. The performance requirements for anything involving graphics are considerable; you want to avoid collection pressure. Making it a struct is a reasonable choice if justified by measurements. – Eric Lippert Feb 16 '12 at 16:59
  • **Structs should be small; no more than, say, four times the size of a reference;** Any link that describes this sentence ? **Your default assumption should be that classes are good enough; only go to a struct when you have evidence that doing so solves a problem that you actually have.** In which context you will like to recommend structure ? – Pankaj Feb 17 '12 at 20:27
  • @PankajGarg: Re: your first request: If you're not going to take my word on it, then why would you take anyone else's? Suppose I tell you to read Cwalina's book; why wouldn't you just then ask *him* for a reference? Re: your second question: use a struct when you are representing a *small immutable value, preferably composed of other values*. – Eric Lippert Feb 17 '12 at 21:15
  • Geeze. Tempted to nuke my answer now. – 3Dave Feb 23 '12 at 20:01
5

If you need the enhanced capabilities that a class offers, such as inheritance, then switch. If not, a struct can be a bit "lighter," but unless you anticipate some performance issues, such as garbage collection inside of a tight loop with a LOT of iterations, the necessity to pass structs around with ref whenever you want a method to make modifications, etc can create unnecessary work. (Though, in that example, destroying a struct that has reference-type properties also causes GC).

The practical upshot being: whether to use a struct or a class is a matter of your use case, not the number of properties that you have.

For a good explanation of the differences between and relative strengths and weakness of classes and structs, see this MSDN article.

For Eric Lippert's excellent note on garbage collection, structs and classes, see his response to this question.

Community
  • 1
  • 1
3Dave
  • 28,657
  • 18
  • 88
  • 151
  • 1
    +1 for most of this answer. I wonder, though, if you could expand on the idea that a struct can be a bit "lighter"? I think that's where the OP is getting his idea that they are more efficient, but with four ints a struct is already going to be "heavier" than a class in many respects. – StriplingWarrior Feb 16 '12 at 16:01
  • @StriplingWarrior good question; one of those things that I picked up awhile back that I can't remember where from. Ill do some reading and update my answer. – 3Dave Feb 16 '12 at 16:09
  • the removal of a struct from the set of live roots can never in itself trigger a GC (unless one was to deliberately write code in the framework to do this, which would be mad). it is the allocatyion of instances on the long lived store that triggers GC (when there is no space in whatever place you wanted to put it). – ShuggyCoUk Feb 16 '12 at 19:34
  • 2
    @StriplingWarrior: Every class instance has associated with it a minimum of 12 bytes' overhead on a 32-bit machine, or 24 bytes' overhead on a 64-bit machine. If one will be creating new instances of a type as much as one will be passing them around, structs will often be lighter weight than class equivalents. – supercat Feb 17 '12 at 04:08
1

I dont think it's a case of if you keep adding strings, it's a case of what do you want to do with the object. Structs are value types and classes are reference types, there are some performance gains of structs from what I understand (in terms of memory heap/stack allocation) but I think ultimiately it depends on what you are doing with the object.

I THINK I read once that structs are great for short-lived lots of them objects, but I could be wrong.

Jeggs
  • 250
  • 1
  • 3
0

If someone says:

  foo x[100];
  foo[1] = foo[2];
  foo[1].a += 5;

should the latter statement affect foo[2].a? If foo is a struct type, it will not; if it's a class type, it will.

Contrary to what Mr. Lippert says, your type may be just fine as a struct, with a couple of caveats:

  1. Structs should expose their fields directly, rather than via properties, unless the properties are going to have some non-trivial logic in them.
  2. Passing by value structs which are larger than 16 bytes is a fair bit slower than passing smaller ones, since .net has special handling for smaller structs. Passing by ref is not affected by struct size, though.
  3. Mutable structs which hold mutable reference types often exhibit semantics which are a weird cross between mutable value semantics and mutable reference semantics. That is not a problem for structs which hold immutable reference types like `string`, however.
  4. Properties of struct type are often a pain to work with. Read-only properties of reference types are sometimes easier to work with, but replacing a struct type that would hold 20 bytes of data, with a class that likewise holds 20 bytes of data, can almost double storage requirements on 32-bit systems, or more than double them on 64-bit systems.

Mutable-value-type semantics are useful. Older C# compilers (years ago) had some problems with them, and some people want to discourage people from learning to understand them, but those aren't good reasons to refrain from using them where appropriate.

supercat
  • 77,689
  • 9
  • 166
  • 211
-3

Remember that what ever you declare in a struct is public by defualt. You have to use a class instead if you want your data to be hidden. Apart from this all typical features of OOP are not available in struct.

FYI: Class (computer programming)

Muhammad Maqsoodur Rehman
  • 33,681
  • 34
  • 84
  • 124
  • Structs are subject to the same access modifiers as classes, as are their properties. Its also a good idea to explicitly declare all entities as public/private/internal, etc. – 3Dave Feb 16 '12 at 16:10
  • 4
    This is a question about C#, not C++. – Eric Lippert Feb 16 '12 at 16:29