I'm in a discussion with a co-worker concerning the use of structs. I have a couple of structs that contain several static properties that are used throughout our website. The value of those properties are all strings. They're not very long, the longest value has 29 characters.
His argument: "I am saying there is no performance gain because there are strings inside of them. For value types yes you gain memory/gc benefits. With strings they are ref types so allocate to the heap and won't give any benefit."
My argument: "...I'm simply treating the string values as value types by using the struct, therefore saving time and gaining performance by not having to instantiate it every time."
Here is an example of one of the structs so that you can see how I'm using them:
public struct Hero
{
public static string Image = "Hero Image";
public static string Eyebrow = "Hero Eyebrow";
public static string Heading = "Hero Heading";
public static string Subheading = "Hero Subheading";
public static string YoutubeLink = "Youtube Hero Link";
public static string PardotForm = "Pardot Form Hero Link";
public static string PardotDirect = "Pardot Direct Hero Link";
public static string DirectLink = "Direct Hero Link";
public static string FacebookLink = "Hero Facebook Link";
public static string TwitterLink = "Hero Twitter Link";
public static string LinkedInLink = "Hero LinkedIn Link";
public static string LinkClassNames = "Class Names";
}
Let me know if I'm completely wrong and should just use classes or if there is a better way of using the structs for my values (i.e: readonly instead of static, etc...).
4 Answers 4
I'll assess what you both said:
-
For value types yes you gain memory/gc benefits.
True.
-
With strings they are ref types so allocate to the heap and won't give any benefit.
True.
-
..I'm simply treating the string values as value types by using the struct
This doesn't make sense. You can't "treat" as value types or reference types. That's determined by how String is implemented. Given that
String
is read-only and un-subclassible in most programming languages, it usually has value semantics (even if it is really implemented as a reference to a heap object) -
therefore saving time and gaining performance by not having to instantiate it every time.
The struct doesn't matter here. String constants are in a static portion of the program, they're not subject to garbage collection, and they're not on the heap.
-
and gaining performance by not having to instantiate it every time.
Access a
static
variable on a type doesn't instantiate the type, regardless of whether it's a struct or class.
Putting these strings in struct vs. a class doesn't matter. As long as they're string constants, they're lazily initialized the first time the struct/class is references.
-
1Don't know about C# but in Java constant strings (Java final) are actually inlined so often the class containing them isn't even loaded. (Also makes for some extra funky things that can happen with reflection if you are not careful)Hangman4358– Hangman43582019年01月22日 22:48:50 +00:00Commented Jan 22, 2019 at 22:48
-
1@Hangman4358 Thats correct in C# aswell, but these arent declared as
const
, the values are all calculated at runtimerichzilla– richzilla2019年01月23日 08:50:03 +00:00Commented Jan 23, 2019 at 8:50 -
When you say strings are not on the heap and not subject to garbage collection, this is not correct. You are confused between constant strings (which are interned to a static table in the program) and dynamic/runtime created strings (which ARE created on the heap and subject to GC). I have debugged many a memory dump for apps with memory problems caused by inefficient string creation.Dave Black– Dave Black2023年10月20日 21:15:17 +00:00Commented Oct 20, 2023 at 21:15
-
@DaveBlack Hmm? I was specifically talking about string constants.Alexander– Alexander2023年10月20日 21:54:39 +00:00Commented Oct 20, 2023 at 21:54
-
You were describing the behavior of constant (compile time) strings. This is very different than runtime behavior of dynamic string creation. Strings are immutable and any change to a string creates a new one.Dave Black– Dave Black2023年10月22日 18:35:14 +00:00Commented Oct 22, 2023 at 18:35
His argument: "I am saying there is no performance gain because there are strings inside of them. For value types yes you gain memory/gc benefits. With strings they are ref types so allocate to the heap and won't give any benefit."
Your coworker is mostly correct.
To put the situation into simple terms:
- It is the type of an object that determines whether it is a value type or a reference type. Every type is either a reference type or a value type. Unless you are the one creating the type, you do not get to choose which.
- The built-in
string
type is, and always will be, a reference type. You cannot turn it into a value type through any means. - It is typically only local variables and parameters that provide the potential for value types to be more efficient.
static
member variables are stored differently and are not governed by quite the same rules. - It does not matter whether
static
fields are kept in astruct
or aclass
because it does not affect how they are stored.
A more in-depth breakdown about the relationship between value types, reference types and storage can be found in this blog post.
The bottom line is that it's a lot more complicated than the usually recited mantra that 'value types go on the stack, reference types go on the heap'. Ultimately whether you chose to make something a struct
or a class
should depend more on other factors.
(See this other answer or this blog post for more details on choosing between struct
and class
.)
-
Swift strings are value types. So are arrays, dictionaries, and structs. The data itself is usually on the heap.gnasher729– gnasher7292022年04月16日 06:06:49 +00:00Commented Apr 16, 2022 at 6:06
-
4@gnasher729 The OP's question is tagged C#, not Swift. Thus what other languages do is largely irrelevant.Pharap– Pharap2022年04月16日 06:37:24 +00:00Commented Apr 16, 2022 at 6:37
strings in a struct as values to static properties
This is a head-splitting description. First, strings are always reference types, no matter how or where you declare them. Your struct will be empty because you have no non-static members. The references will take up 4 * 12 bytes in size. Where the characters are will no longer matter, they will remain in the same place for the lifetime of your process. If you want the text to be laid out in a struct you must use character arrays instead and declared them non-static.
Second, there are no properties in your example. You only have data members.
Performance-wise you gain nothing by having strings contained in a struct. You may even lose performance if you are not careful by cause boxing and unboxing.
Either way, for accessing the strings it would not bear significance. Reading a string of only a couple of characters will already take longer than finding the first character, which is really what this is about. And this ratio will quickly increase as the string gets longer.
-
1"Your struct will be 4 * 12 bytes in size" -> No it won't, because these are static fields.Alexander– Alexander2019年01月22日 22:23:46 +00:00Commented Jan 22, 2019 at 22:23
-
"You may even lose performance if you are not careful by cause boxing and unboxing." There's no boxing/unboxing going on, because there are no struct instancesAlexander– Alexander2019年01月22日 22:24:14 +00:00Commented Jan 22, 2019 at 22:24
-
@Alexander We do not know if he has struct instances or not, for all we know he may create an instance and pass that Hero around as an argument to a method as a ref parameter. The struct itself is not declared static. I realize you are right with your first comment, I will edit.Martin Maat– Martin Maat2019年01月22日 22:35:07 +00:00Commented Jan 22, 2019 at 22:35
-
I don't create instances of my structs I access them directly wherever needed and I never see the need to use them as ref parameters.Necromancer– Necromancer2019年01月23日 14:12:56 +00:00Commented Jan 23, 2019 at 14:12
Neither one of you bothered to benchmark your claims, so performance becomes a moot point.
Your suggestion of a struct
in this case is therefore wrong, because it is a deviation from the norm, which would be a static class with const
strings. The time a maintenance developer spends wondering why this code is a struct instead of a class is going to dwarf the performance you may or may not gain.
struct
have to do with this? Statics don't much care if they're in a struct or not. Though... you probably want to make theseconst
or at leastreadonly
to prevent someone rewriting your globals :P