Struct vs Class?
-
As a self taught ameture in c#, I have never found a reason to implement a struct instead of a class. Since I am self taught (No formal education) I would like to know what advantage would be gained by using a struct in lieu of a class? More importantly why when and where would it benefit my programs? To this point I have created applications for my own use or for my family. simple utilities and a few web applications. Thanks in advance for any input.
David
-
As a self taught ameture in c#, I have never found a reason to implement a struct instead of a class. Since I am self taught (No formal education) I would like to know what advantage would be gained by using a struct in lieu of a class? More importantly why when and where would it benefit my programs? To this point I have created applications for my own use or for my family. simple utilities and a few web applications. Thanks in advance for any input.
David
Read these: 1. Choosing Between Class and Struct[^] 2. Class and struct differences[^]
-
As a self taught ameture in c#, I have never found a reason to implement a struct instead of a class. Since I am self taught (No formal education) I would like to know what advantage would be gained by using a struct in lieu of a class? More importantly why when and where would it benefit my programs? To this point I have created applications for my own use or for my family. simple utilities and a few web applications. Thanks in advance for any input.
David
That's a lot bigger question that you probably thought - it involves a lot of background before you can make a decision to use one or the other. So, let's have a little (hah - it was quite a lot) background... Struct and Class have one huge difference: struct is a value type, class is a reference type. What that means is simple to describe, but harder to grasp the significance of. So let's start by defining one of each:
public class MyClass
{
public int I;
public int J;
}
public struct MyStruct
{
public int I;
public int J;
}The two objects are identical, except that one is a class and one is a struct. Which means that if you declare an instance of each in your code then you get a reference and a value, but the code can look the same:
public void UseClassAndStruct()
{
MyClass mc = new MyClass();
mc.I = 1;
mc.J = 2;
MyStruct ms = new MyStruct();
ms.I = 1;
ms.J = 2;
}Or slightly different:
public void UseClassAndStruct()
{
MyClass mc = new MyClass();
mc.I = 1;
mc.J = 2;
MyStruct ms;
ms.I = 1;
ms.J = 2;
}Because you don't have to use the
new
keyword with structs. If you do, then the struct constructor is called, if you don't it isn't - simple as that. Unlike a class, the name of the struct is the struct itself, it is not a "pointer" to a instance. And that's important, because that is the whole point: a struct is the object, and class is a reference to the object. When you create a class variable:MyClass mc;
That allocates memory on the stack to hold a reference to a MyClass instance in future, it does not create an instance of MyClass, and you will have seen that before when you try to use any property or method of a class and you get a "Object reference not set to an instance of an object" exception and your program crashes. You have to explicitly create an instance of the class by using the
new
keyword:mc = new MyClass();
What this does is create a new instance of MyClass on the heap, and assign the reference to it to the variable
mc
. This is important, because the stack and the heap are different "types" of memory: the heap is a big "lump" or memory which is sorted out by the Garbage collector and all classes, methods and threads share it. The stack on the other hand is specific to a thread, and everything on the stack is discarded when you -
That's a lot bigger question that you probably thought - it involves a lot of background before you can make a decision to use one or the other. So, let's have a little (hah - it was quite a lot) background... Struct and Class have one huge difference: struct is a value type, class is a reference type. What that means is simple to describe, but harder to grasp the significance of. So let's start by defining one of each:
public class MyClass
{
public int I;
public int J;
}
public struct MyStruct
{
public int I;
public int J;
}The two objects are identical, except that one is a class and one is a struct. Which means that if you declare an instance of each in your code then you get a reference and a value, but the code can look the same:
public void UseClassAndStruct()
{
MyClass mc = new MyClass();
mc.I = 1;
mc.J = 2;
MyStruct ms = new MyStruct();
ms.I = 1;
ms.J = 2;
}Or slightly different:
public void UseClassAndStruct()
{
MyClass mc = new MyClass();
mc.I = 1;
mc.J = 2;
MyStruct ms;
ms.I = 1;
ms.J = 2;
}Because you don't have to use the
new
keyword with structs. If you do, then the struct constructor is called, if you don't it isn't - simple as that. Unlike a class, the name of the struct is the struct itself, it is not a "pointer" to a instance. And that's important, because that is the whole point: a struct is the object, and class is a reference to the object. When you create a class variable:MyClass mc;
That allocates memory on the stack to hold a reference to a MyClass instance in future, it does not create an instance of MyClass, and you will have seen that before when you try to use any property or method of a class and you get a "Object reference not set to an instance of an object" exception and your program crashes. You have to explicitly create an instance of the class by using the
new
keyword:mc = new MyClass();
What this does is create a new instance of MyClass on the heap, and assign the reference to it to the variable
mc
. This is important, because the stack and the heap are different "types" of memory: the heap is a big "lump" or memory which is sorted out by the Garbage collector and all classes, methods and threads share it. The stack on the other hand is specific to a thread, and everything on the stack is discarded when you+5! :thumbsup: You could easily copy & paste that into a new Tip/Trick (or even article) :laugh:
-
That's a lot bigger question that you probably thought - it involves a lot of background before you can make a decision to use one or the other. So, let's have a little (hah - it was quite a lot) background... Struct and Class have one huge difference: struct is a value type, class is a reference type. What that means is simple to describe, but harder to grasp the significance of. So let's start by defining one of each:
public class MyClass
{
public int I;
public int J;
}
public struct MyStruct
{
public int I;
public int J;
}The two objects are identical, except that one is a class and one is a struct. Which means that if you declare an instance of each in your code then you get a reference and a value, but the code can look the same:
public void UseClassAndStruct()
{
MyClass mc = new MyClass();
mc.I = 1;
mc.J = 2;
MyStruct ms = new MyStruct();
ms.I = 1;
ms.J = 2;
}Or slightly different:
public void UseClassAndStruct()
{
MyClass mc = new MyClass();
mc.I = 1;
mc.J = 2;
MyStruct ms;
ms.I = 1;
ms.J = 2;
}Because you don't have to use the
new
keyword with structs. If you do, then the struct constructor is called, if you don't it isn't - simple as that. Unlike a class, the name of the struct is the struct itself, it is not a "pointer" to a instance. And that's important, because that is the whole point: a struct is the object, and class is a reference to the object. When you create a class variable:MyClass mc;
That allocates memory on the stack to hold a reference to a MyClass instance in future, it does not create an instance of MyClass, and you will have seen that before when you try to use any property or method of a class and you get a "Object reference not set to an instance of an object" exception and your program crashes. You have to explicitly create an instance of the class by using the
new
keyword:mc = new MyClass();
What this does is create a new instance of MyClass on the heap, and assign the reference to it to the variable
mc
. This is important, because the stack and the heap are different "types" of memory: the heap is a big "lump" or memory which is sorted out by the Garbage collector and all classes, methods and threads share it. The stack on the other hand is specific to a thread, and everything on the stack is discarded when you -
Pretty good, but Griff, you know ints etc are immutable, right? You can't exactly change the value of 3..
I've worked with dialects of FORTRAN where you can... :wtf:
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
-
Pretty good, but Griff, you know ints etc are immutable, right? You can't exactly change the value of 3..
They are and they aren't, but that's kinda the advanced school: who needs to know that
i = i + 1;
creates a new integer instance and loads a copy into the original location? Particularly when it doesn't - If you have a look at the IL it fetches the value, increments it, and stores the new value back - no new instance is explicitly created except in the sense that the load removes the early version instance from the stack and then iteh new value is put back in the same place:
.line 14,14 : 13,25 'int i = 777;' IL\_0001: ldc.i4 0x309 IL\_0006: stloc.0 .line 15,15 : 13,23 'i = 1 + 1;' IL\_0007: ldloc.0 IL\_0008: ldc.i4.1 IL\_0009: add IL\_000a: stloc.0
But it does indeed behave as if they were, specifically to prevent constant values being modified by our code! :laugh:
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
-
They are and they aren't, but that's kinda the advanced school: who needs to know that
i = i + 1;
creates a new integer instance and loads a copy into the original location? Particularly when it doesn't - If you have a look at the IL it fetches the value, increments it, and stores the new value back - no new instance is explicitly created except in the sense that the load removes the early version instance from the stack and then iteh new value is put back in the same place:
.line 14,14 : 13,25 'int i = 777;' IL\_0001: ldc.i4 0x309 IL\_0006: stloc.0 .line 15,15 : 13,23 'i = 1 + 1;' IL\_0007: ldloc.0 IL\_0008: ldc.i4.1 IL\_0009: add IL\_000a: stloc.0
But it does indeed behave as if they were, specifically to prevent constant values being modified by our code! :laugh:
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
I disagree with this analysis on many levels. Firstly, immutability is about semantics, not implementation, so showing some IL or even assembly doesn't show anything. Secondly, the semantics of the "add" IL instruction are "pop two values, add them, push result". So if you want to treat stack slots as instances (and I disagree with that as well), the old ones are gone and you have a new one. Thirdly, extending this sort of analysis to assembly gives absurd conclusions. For example, what happens in "add eax, 1"? Obviously one is added to "eax", but that doesn't mean that if "eax" had the value 0 first that you've just "changed the value of the 0-instance".
-
I disagree with this analysis on many levels. Firstly, immutability is about semantics, not implementation, so showing some IL or even assembly doesn't show anything. Secondly, the semantics of the "add" IL instruction are "pop two values, add them, push result". So if you want to treat stack slots as instances (and I disagree with that as well), the old ones are gone and you have a new one. Thirdly, extending this sort of analysis to assembly gives absurd conclusions. For example, what happens in "add eax, 1"? Obviously one is added to "eax", but that doesn't mean that if "eax" had the value 0 first that you've just "changed the value of the 0-instance".
I know what you mean, but... That's not the way I see immutable: I see it as "can't be changed" which is applicable to the constant values 1, 2, 3, etc., but not to the variables which are initialised to the constant value and operated on from there. I would agree that 1 is immutable - to do otherwise induces madness - but I'm not convinced that variables containing what can also be considered as a constant are immutable. If the physical location is the same, but the content has changed and nothing else, then my feeling is that it has changed and is thus not immutable. Certainly in the case of string the immutability is obvious (if hidden behind the scenes): once a string is created, it can never be changed again, just copied or deleted - even if the scene changers disguise this and appear to allow it! :laugh:
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
-
I know what you mean, but... That's not the way I see immutable: I see it as "can't be changed" which is applicable to the constant values 1, 2, 3, etc., but not to the variables which are initialised to the constant value and operated on from there. I would agree that 1 is immutable - to do otherwise induces madness - but I'm not convinced that variables containing what can also be considered as a constant are immutable. If the physical location is the same, but the content has changed and nothing else, then my feeling is that it has changed and is thus not immutable. Certainly in the case of string the immutability is obvious (if hidden behind the scenes): once a string is created, it can never be changed again, just copied or deleted - even if the scene changers disguise this and appear to allow it! :laugh:
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
I completely agree that a variable of type int is not immutable, but that doesn't really matter since immutability is a property of a type, not of a variable of that type (obviously a variable is, well, variable). Funny that you should mention strings, they're less immutable than integers, but most people agree that they should be called immutable anyway because the only way to mutate an instance is by cheating (reflection or unsafe). You can't even mutate an instance of an int by cheating.
-
As a self taught ameture in c#, I have never found a reason to implement a struct instead of a class. Since I am self taught (No formal education) I would like to know what advantage would be gained by using a struct in lieu of a class? More importantly why when and where would it benefit my programs? To this point I have created applications for my own use or for my family. simple utilities and a few web applications. Thanks in advance for any input.
David
Hi David, I'm writing up my response to your question as a simple article, and with your permission, I'd like to include an extract from your question in that:
David C# Hobbyist. wrote:
As a self taught ameture in c#, I have never found a reason to implement a struct instead of a class.
Since I am self taught (No formal education) I would like to know what advantage would be gained by using a struct in lieu of a class? More importantly why when and where would it benefit my programs?If you agree, I can tidy up the spelling, and either credit you or leave it anonymous - whichever you prefer - but I think it would help the "flow" of the article to explain why it exists. If you don't agree for whatever reason (or none!), that's no problem either, I just won't reference you and will come up with a different introduction! :laugh: Please do reply whichever way you decide - but if you don't I will of course assume you are refusing permission and not reference you in any way.
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
-
That's a lot bigger question that you probably thought - it involves a lot of background before you can make a decision to use one or the other. So, let's have a little (hah - it was quite a lot) background... Struct and Class have one huge difference: struct is a value type, class is a reference type. What that means is simple to describe, but harder to grasp the significance of. So let's start by defining one of each:
public class MyClass
{
public int I;
public int J;
}
public struct MyStruct
{
public int I;
public int J;
}The two objects are identical, except that one is a class and one is a struct. Which means that if you declare an instance of each in your code then you get a reference and a value, but the code can look the same:
public void UseClassAndStruct()
{
MyClass mc = new MyClass();
mc.I = 1;
mc.J = 2;
MyStruct ms = new MyStruct();
ms.I = 1;
ms.J = 2;
}Or slightly different:
public void UseClassAndStruct()
{
MyClass mc = new MyClass();
mc.I = 1;
mc.J = 2;
MyStruct ms;
ms.I = 1;
ms.J = 2;
}Because you don't have to use the
new
keyword with structs. If you do, then the struct constructor is called, if you don't it isn't - simple as that. Unlike a class, the name of the struct is the struct itself, it is not a "pointer" to a instance. And that's important, because that is the whole point: a struct is the object, and class is a reference to the object. When you create a class variable:MyClass mc;
That allocates memory on the stack to hold a reference to a MyClass instance in future, it does not create an instance of MyClass, and you will have seen that before when you try to use any property or method of a class and you get a "Object reference not set to an instance of an object" exception and your program crashes. You have to explicitly create an instance of the class by using the
new
keyword:mc = new MyClass();
What this does is create a new instance of MyClass on the heap, and assign the reference to it to the variable
mc
. This is important, because the stack and the heap are different "types" of memory: the heap is a big "lump" or memory which is sorted out by the Garbage collector and all classes, methods and threads share it. The stack on the other hand is specific to a thread, and everything on the stack is discarded when you+5 very useful response ! I find it hard to conceptualize structs as "immutable" when I can do stuff like that shown in the code for 'TestStruct below; and, so do other people:
public struct MyStruct
{
public string Name;
public int X;
public int Y;public int Z { set; get; } public MyStruct(int z) : this() { Z = z; }
}
public void increment(ref MyStruct aStruct, int inc )
{
aStruct.X += inc;
}private void WriteSValues(params MyStruct[] theStructs)
{
foreach (var theStruct in theStructs)
{
Console.WriteLine("Name: {0} X: {1} Y: {2} X: {3}",
theStruct.Name,
theStruct.X,
theStruct.Y,
theStruct.Z);
}
Console.WriteLine();
}// test
private void TestStruct()
{
MyStruct ms1 = new MyStruct(300) {Name = "ms1", X = 100, Y = 200};
ms1.X += -300;MyStruct ms2 = ms1; ms2.Name = "ms2"; WriteSValues(ms1, ms2); increment(ref ms1, 200); WriteSValues(ms1, ms2); ms1.X += 500; WriteSValues(ms1, ms2); MyStruct ms3 = ms2; ms3.Name = "ms3"; WriteSValues(ms1, ms2, ms3); increment(ref ms3, 1000); WriteSValues(ms1, ms2, ms3);
}
The above is a diagnostic quiz I wrote for some supposedly "intermediate" C# students (not students of mine): their task was to describe the values for each struct created, at each line of the code, and explain why the values were what they were. About half understood that assigning an instance of a struct to another instance of a struct of the same Type created a copy, but they all were quite confused by the other bits in the code. The quiz was administered by their regular teacher, so I don't think the results exhibit bias due to shyness in the presence of someone from outside their social process.
“But I don't want to go among mad people,” Alice remarked. “Oh, you can't help that,” said the Cat: “we're all mad here. I'm mad. You're mad.” “How do you know I'm mad?” said Alice. “You must be," said the Cat, or you wouldn't have come here.” Lewis Carroll
-
Hi David, I'm writing up my response to your question as a simple article, and with your permission, I'd like to include an extract from your question in that:
David C# Hobbyist. wrote:
As a self taught ameture in c#, I have never found a reason to implement a struct instead of a class.
Since I am self taught (No formal education) I would like to know what advantage would be gained by using a struct in lieu of a class? More importantly why when and where would it benefit my programs?If you agree, I can tidy up the spelling, and either credit you or leave it anonymous - whichever you prefer - but I think it would help the "flow" of the article to explain why it exists. If you don't agree for whatever reason (or none!), that's no problem either, I just won't reference you and will come up with a different introduction! :laugh: Please do reply whichever way you decide - but if you don't I will of course assume you are refusing permission and not reference you in any way.
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
Absolutely and thanks for the long winded reply. I am just now reading it as well as the info in the links posted by @Peter-Leow. I have some studying to do. Thank You for the help in understanding the difference.:thumbsup: [Edit] Please inform me when it is posted I would like to read it.[/Edit]
David
-
Absolutely and thanks for the long winded reply. I am just now reading it as well as the info in the links posted by @Peter-Leow. I have some studying to do. Thank You for the help in understanding the difference.:thumbsup: [Edit] Please inform me when it is posted I would like to read it.[/Edit]
David
Thank you -and you're welcome! I certainly will. :thumbsup:
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
-
I know what you mean, but... That's not the way I see immutable: I see it as "can't be changed" which is applicable to the constant values 1, 2, 3, etc., but not to the variables which are initialised to the constant value and operated on from there. I would agree that 1 is immutable - to do otherwise induces madness - but I'm not convinced that variables containing what can also be considered as a constant are immutable. If the physical location is the same, but the content has changed and nothing else, then my feeling is that it has changed and is thus not immutable. Certainly in the case of string the immutability is obvious (if hidden behind the scenes): once a string is created, it can never be changed again, just copied or deleted - even if the scene changers disguise this and appear to allow it! :laugh:
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
OriginalGriff wrote:
That's not the way I see immutable:
Similar problem exists with 'const' in C++. In terms of semantics for that I differentiate between 'binary constant' and 'logical constant'. The first means that the structure of the memory for the data will not change. The second means that for a user of the entity that it will not change. And example of this is a class that represents application properties that cannot be changed by the application itself but which use a memory cache which might be refreshed for various reasons.
-
Absolutely and thanks for the long winded reply. I am just now reading it as well as the info in the links posted by @Peter-Leow. I have some studying to do. Thank You for the help in understanding the difference.:thumbsup: [Edit] Please inform me when it is posted I would like to read it.[/Edit]
David
It's published: Using struct and class - what's that all about?[^] It's much the same as the answer, but with some added material to cover embedded structs, and arrays. Thank you again!
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
-
It's published: Using struct and class - what's that all about?[^] It's much the same as the answer, but with some added material to cover embedded structs, and arrays. Thank you again!
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)
Thanks, I read it this morning. I found a couple of times in my code where a struct would have been a better choice. But "If it aint broke".
David
-
Thanks, I read it this morning. I found a couple of times in my code where a struct would have been a better choice. But "If it aint broke".
David
..."don't fix it" Wise decision! :laugh:
Those who fail to learn history are doomed to repeat it. --- George Santayana (December 16, 1863 – September 26, 1952) Those who fail to clear history are doomed to explain it. --- OriginalGriff (February 24, 1959 – ∞)