When, why and where should a struct be used?

M

Michael Nemtsev

T

the.duckman

I will try to give a simle answer gloassing over as many technical
issues as I can...

Structs are an "old school" method of combineing data elements into one
unit.

Class came along afterwards, they are esentuly a struct which allows
for things like inheritance and other OO stuff.

Structs being somewhat simpler creatures are "lean and mean", that is
they work fast but lack features.

Example .NET stucts Point, Rectangle DateTime. Note how these are
simple operations which are often performance critical.

Classes are usefull when things get more complicated. Ie you need
inheritance or something.

Struct and Classes have different pitfals that may suprise the new
programmer.
ie

a struct can not be nul but a class can..
struct a = stuct b copyies bto a
class a = class b means a is also called b.

hope this "basic" overview helps.

-dm
 
J

Jon Skeet [C# MVP]

Structs being somewhat simpler creatures are "lean and mean", that is
they work fast but lack features.

This is a vast oversimplification. Structs are very often *not* the
faster (or leaner) solution. For instance, if you have a struct with
100 fields in, that will be much larger and slower to pass as a
parameter into a method than a single reference would be.

One day I'll get round to writing up a full article on types and
particularly the difference between value types and reference types.
They are fundamentally different - it's not that one is a "leaner and
meaner" version of the other.
 
I

Ian Semmel

Jon said:
This is a vast oversimplification. Structs are very often *not* the
faster (or leaner) solution. For instance, if you have a struct with
100 fields in, that will be much larger and slower to pass as a
parameter into a method than a single reference would be.

One day I'll get round to writing up a full article on types and
particularly the difference between value types and reference types.
They are fundamentally different - it's not that one is a "leaner and
meaner" version of the other.

Why are structs passed as value parameters ? What's the difference (logically)

eg Given a function
void fn ( typea p1, typeb p2 )
{
}

which is the value parameter if one of the types is a class and one a struct ?

Why differentiate between classes and simple types rather than say having all
parameters passed by reference and having a val keyword ( or vice versa) ?

I'm sure there's a good reason, but I don't know C# well enough.

In C++, I typically use structs to describe say the structure of a byte stream eg

#pragma pack ( push, 1 )
typedef struct Hdr
{
unsigned char soh;
unsigned char fld [ 2 ];
}
Hdr;

etc
 
N

Nick Hounsome

Ian Semmel said:
Why are structs passed as value parameters ? What's the difference
(logically)

Because that is (partly) what structs are for in C#
eg Given a function
void fn ( typea p1, typeb p2 )
{
}

which is the value parameter if one of the types is a class and one a
struct ?

the struct is.
Why differentiate between classes and simple types rather than say having
all parameters passed by reference and having a val keyword ( or vice
versa) ?

This is to do with the fact that value types (structs) can be on the stack
or inside objects on the heap whereas reference types (classes) cannot.
These limitations ensure that there are references into the stack or into
the guts of an object on the heap. If there were then GC would be extremely
difficult if not impossible consequently you cannot pass structs by
reference.

I suppose that in principle you could pass reference types by value but what
would be the point.
I'm sure there's a good reason, but I don't know C# well enough.

In C++, I typically use structs to describe say the structure of a byte
stream eg

There is no way to know or influence the memory layout of anything in C#
(although there are ways to influence how something is marshalled when
calling C/C++ this is NOT the same as saying how it is stored in memory).

struct and class are virtually synonymous in C++ whereas they are quite
different in C#
 
J

Jon Skeet [C# MVP]

Ian said:
Why are structs passed as value parameters ? What's the difference (logically)

eg Given a function
void fn ( typea p1, typeb p2 )
{
}

which is the value parameter if one of the types is a class and one a struct ?

Both are. Both parameters are passed by value. One of the parameters is
itself a reference, the other isn't.
Why differentiate between classes and simple types rather than say having all
parameters passed by reference and having a val keyword ( or vice versa) ?

That's exactly what we've got - pass by value is the default, and you
can specify to pass by reference. However, you need to be aware that
what you're passing in the case of a reference type is a reference.
That's not the same as pass-by-reference semantics, although it's
similar in many respects.

See http://www.pobox.com/~skeet/csharp/parameters.html for more details
on this.

When you do something like:

ArrayList a = new ArrayList();
the value of a is a reference to an ArrayList - it isn't the ArrayList
object itself.

Now, when you do:
int x = 5;
the value of x *is* the integer.
I'm sure there's a good reason, but I don't know C# well enough.

In C++, I typically use structs to describe say the structure of a byte stream eg

<snip>

C++ is somewhat different, I believe. I don't know C++ well enough to
talk confidently about it, but I *believe* that a struct in C# is
roughly equivalent to a class in C++. When you declare a variable
(parameter, whatever) in C#, that's like declaring the variable as a
pointer in C++:

C#: SomeType a;
C++: SomeType *a;

As I say, some of the C++ terminology *may* be a little off here - I
apologise if so.

Jon
 
J

Jon Skeet [C# MVP]

Nick said:
Because that is (partly) what structs are for in C#


the struct is.

No - both are value parameters. In both cases, the value of the
expression used as the argument is evaluated, and that value becomes
the initial value of the parameter.
From the C# spec:

<quote>
A parameter declared without a ref or out modifier is a value
parameter.
</quote>

Here, neither parameter is declared with a ref or out modifier, so both
are value parameters.

Jon
 
B

Bruce Wood

Sorry, but you're wrong on most counts. You're thinking of "struct" as
it exists in C++ or C, not C#. C# structs are very different. Read the
links to the threads given in the other posts.

I will try to give a simle answer glossing over as many technical
issues as I can...

Structs are an "old school" method of combineing data elements into one
unit.

In C++ this is true. It is not true in C#. In fact, using them this way
in C# is a sure road to frustration and bad code.
Class came along afterwards, they are esentuly a struct which allows
for things like inheritance and other OO stuff.

Historically, in C++, this is true, but not for C#. Everything changed
in C#.
Structs being somewhat simpler creatures are "lean and mean", that is
they work fast but lack features.

A vast oversimplification that overlooks the primary difference between
struct and class in C#: classes are reference types and structs are
value types. This has implications for how they are assigned, passed to
methods, and returned as results from methods and properties. It also
has implications for garbage collection. All of this means that structs
_may_ give you a performance increase, or _may_ cause performance
degradation, depending upon how you use them.

Unless you understand the difference between value semantics and
reference semantics and why and when one would want one rather than the
other, you will not know where it's appropriate to use a value type
(struct) to gain efficiencies.

Anyway, most value types you'll create will be because you want value
semantics, not for the sake of speed. There are only a few cases I can
think of where something was made a value type for efficiency's sake;
those are Point and Rectangle, and even then the Framework designers
had to make a decision to subtly change their semantics: a Point struct
has different semantic implications from a Point class.
Example .NET stucts Point, Rectangle DateTime. Note how these are
simple operations which are often performance critical.

Well, yes, but you don't say why. The reason is garbage collection: if
you're doing thousands or millions of coordinate calculations, then you
don't want to be stuck garbage collecting thousands or millions of
little Points off the heap. Making it a struct means that it doesn't
need to be GC'd. However, making it a struct changes its semantics
subtly: a Point now becomes a _value_, and as such there's no more
concept of "this point 4,6" as opposed to "that point 4,6". The
coordinates 4,6 become a value that is copied everywhere, just like
"the integer 5". A Point class would give you the possibility of
(cleanly) having several copies of 4,6 that were distinct and could be
manipulated.
Classes are usefull when things get more complicated. Ie you need
inheritance or something.

No... classes are useful when you want reference semantics, which is
almost always, and certainly whenever you have objects that have
_identity_: a customer, a sales order, the sales figures for a
particular year, stuff like that.
struct a = stuct b copyies bto a
class a = class b means a is also called b.

True, but these are hardly "pitfalls": this behaviour is the very
reason why you would choose one over the other.

As I said, please read the other threads that were linked earlier in
this thread. Those discussions clearly outline the pros and cons of
structs versus classes.
 
B

Bruce Wood

Check out the following for information on the difference between a
value and a reference in C#:

http://www.albahari.com/value vs reference types.html

Not a bad article on the low-level handling of classes versus structs
where memory allocation is concerned, although it contains a few minor
bloopers:

In fact, the only value types for which the CLR leaves space in a stack
frame are method arguments, local variables, and method results. The
article mentions only later that value types that are fields in classes
are created on the heap along with all of the other information for the
class instance.

Well, yes, but there's another way that the Dispose method is called,
and that's by the garbage collector just before it reclaims an object.
So, it's not _entirely_ necessary that Dispose be called on an object
before it goes out of scope... it's just better practice because it
releases unmanaged resources sooner. (At least, that's my
understanding... someone please correct me if I'm wrong.)

The author mentions two relatively unimportant consequences of making
Size a class and forgets to mention the most important one: if you are
creating many, many Sizes, Points, or Rectangles (which the WinForms
classes do on a regular basis) and they were classes, then every one of
those little things would have to be cleaned up by the garbage
collector at some point. Making them value types means that they never
need to be GC'd (unless they're boxed).

As I said, not a bad article, but it doesn't really tell you why you'd
want to make something a class rather than a struct or vice versa.
 
C

clintonG

As I said, not a bad article, but it doesn't really tell you why you'd

And that's what I'm still trying to figure out -- beyond the value/reference
context -- but this topic sure stirs it up yea heh?

<%= Clinton Gallagher
 
B

Bill Butler

C++ is somewhat different, I believe. I don't know C++ well enough to
talk confidently about it, but I *believe* that a struct in C# is
roughly equivalent to a class in C++.

Hi Jon,

It has been a while, however, if I remember correctly.

In C++ there is NO difference between a class and a struct EXCPEPT
The default access qualifier for members is public for structs
The default access qualifier for members is private for classes

Bill
 
I

Ian Semmel

Jon said:
No - both are value parameters. In both cases, the value of the
expression used as the argument is evaluated, and that value becomes
the initial value of the parameter.


<quote>
A parameter declared without a ref or out modifier is a value
parameter.
</quote>

Here, neither parameter is declared with a ref or out modifier, so both
are value parameters.

Jon

Actually, I've worked it out (to my way of thinking )

C#
void fn ( cl p )
C++
void fn ( cl* p)

C#
void fn ( ref cl p )
C++
void fn ( cl*& p )

C#
void fn ( struc_thing s )
C++
void fn ( struc_thing s )
 
B

Bruce Wood

Well, as I said in the other thread. 99.9% of the time you want a
class.

You want a struct when you want the thing to act like a primitive
type-for example, if you want to do mathematics with it-and you
don't terribly mind that it won't have any sort of identity: it will be
copied all over the place and one copy is semantically the same as any
other.

What I mean by that last bit is that, for example "customer" would make
for a lousy struct: usually you think of having one instance for each
customer, with everyone pointing at the same instance (for a single
customer). You create copies for specific reasons, like making a new
version to write back the database (as opposed to the original one you
read in, which you might be holding somewhere). You don't really think
of a customer as a "value" that is copied whenever it's assigned. Most
types you create will be like this.

However, a few things, like a Fraction (one of my value types), you
_do_ want it to act like a primitive type (the same way that decimal
acts, for example): you want to do math with it, and every time you
assign it or do some operation on it you want the result to be a copy:
you don't want to alter the number 1.5 so that every variable holding
1.5 now contains 1.7. That makes no sense. Similarly, you don't want to
modify 3 3/4 so that every variable holding it now holds 5 1/2. You
want to do some operation that results in a new value, 5 1/2, and then
store it in some variable, just the way that a decimal type works.

Take a look at the standard type System.Drawing.Point, and notice the
subtle difference between making it a class and making it a struct.

One fellow posted here that he wanted to create a drawing program that
allowed his users to place points on the screen and join them into
polygons. Then allow the user to manipulate the vertices of the polygon
on the screen. He was wondering how to do that with the standard Point
value type. The answer is that he would be better off creating a new
_class_ called Vertex, which might use Point to store its coordinates,
but which is a _class_. Why? Because if the user were to place two
vertices of two polygons at the location (4, 6), you want them to
remain distinct vertices. Since a value type has no "identity" (one
copy of (4, 6) is equivalent to any other copy of (4, 6)), this doesn't
work too well with value types. You need a class, because Vertex
objects as reference types would have _identity_: _this_ (4, 6) is
distinct from _that_ (4, 6).

By making Point a struct, MS gained some GC efficiency, but also gave
it specific semantics: Points are commodities. The only thing that
distinguishes one from another are its coordinates, its value, and if
two have the same coordinates then you can't tell whether they're
distinct points or just copies of one another. This the same as when
you have two variables containing the value 5: any distinction between
them exists only in code. There is no way that you can "mark" this
value 5 to distinguish it from that value 5. It's just 5. Classes are
different: two instances are distinct even if they contain the same
data, because they have different references (different addresses).

Anyway, you almost never want value semantics in a type you create. You
almost always want your types to have reference semantics: each
instance you create is distinct from all other instances (even if it
contains the same state, the same values in its members), and if you
want to create a copy of one you do so explicitly (via Clone).

It's only in those few cases in which you want a new type that acts
like a primitive, like int or double or DateTime, that you would use
struct.

Finally, if you do create a struct, and you think that you need it to
be mutable (you need property setters, or methods that change a value
rather than returning a new value) then you are probably abusing the
construct. This rule is not 100%: notice that Microsoft made Point
mutable, for example (you can say myPoint.X = 6), a decision with which
I don't entirely agree, by the way. The linked article showed the kinds
of (apparently) odd behaviour that can result, so I prefer immutable
structs on those rare occasions when I create one.
 
J

Jon Skeet [C# MVP]

Bill Butler said:
It has been a while, however, if I remember correctly.

In C++ there is NO difference between a class and a struct EXCPEPT
The default access qualifier for members is public for structs
The default access qualifier for members is private for classes

I thought you couldn't put methods in a struct in C++?
 
B

Bruce Wood

C++ is somewhat different, I believe. I don't know C++ well enough to
talk confidently about it, but I *believe* that a struct in C# is
roughly equivalent to a class in C++.

I wouldn't say that. There are enough differences between the
languages, particularly where argument passing is involved, that it's
difficult to draw parallels.

C++ has nothing like C# structs. Argument passing aside, every type you
create in C++ is a reference type. If you want value semantics, or
something close to it, in C++ you use copy constructors to get that
effect. I don't recall any way in C++ to create your own type that when
declared as a local variable is allocated directly on the stack.
Someone can correct me if I'm wrong (my C++ brain cells are dying off
slowly).

The best advice I can give to C/C++ programmers coming to C# is this:
do not confuse C/C++ "struct" with C# "struct". They are completely
different animals. Forget everything you know about what "struct" means
and read the C# documentation with an open mind. Any "knowledge" you
bring with you from C/C++, where structs are concerned, can only hurt
you. At least, I kept messing them up until I decided to forget what I
"knew" and really read the doc. That's when the penny dropped.
 
B

Bruce Wood

I don't recall any way in C++ to create your own type that when
declared as a local variable is allocated directly on the stack.

OK... maybe I'm being a dunce, here. One of my half-dead C++ brain
cells just told me that this can be done with _any_ type: just declare
a variable as being of that type rather than a pointer to that type.

Regardless, one thing I'm sure of is that in C++ classes and structs
are essentially the same thing, just that structs are sort of
"class-lite". This is absolutely not so in C#: structs act very
differently from classes, so much so that I would say that the C#
"struct" is a brand new beast that really doesn't have a parallel in
C++.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top