www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - enum str = "abc"; vs string str = "abc";

reply Victor Porton <porton narod.ru> writes:
What is more space efficient:

enum str = "safjkdfjksdlfkdsj";

or

string str = "safjkdfjksdlfkdsj";

?

with the first code fragment, won't the string be re-created and 
re-inserted into the object file one time whenever str is used, 
rather than once?

What of the two you would recommend?
Jan 16
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jan 16, 2019 at 06:21:29PM +0000, Victor Porton via Digitalmars-d wrote:
 What is more space efficient:
 
 enum str = "safjkdfjksdlfkdsj";
 
 or
 
 string str = "safjkdfjksdlfkdsj";
 
 ?
 
 with the first code fragment, won't the string be re-created and
 re-inserted into the object file one time whenever str is used, rather
 than once?
Strings are a bit special, in that the compiler automatically stores them in a string table and emits them only once. However, you're quite right that using enum with arrays in general is not a good idea space-wise.
 What of the two you would recommend?
Use: immutable str = "..."; in module-global scope. Or if this is inside a function, static immutable str = "..."; This places it in the data section of the object file and elides the extra pointer/size pair of `str` if it were mutable. OTOH, if `str` is only referenced at compile-time, then it's more efficient to use the enum, because then it won't even appear in the object file. :-) Also, you may have no choice but to use an enum if `str` is referenced by compile-time code, since static globals would not be readable at compile-time. T -- Study gravitation, it's a field with a lot of potential.
Jan 16
next sibling parent Victor Porton <porton narod.ru> writes:
On Wednesday, 16 January 2019 at 18:50:51 UTC, H. S. Teoh wrote:
 On Wed, Jan 16, 2019 at 06:21:29PM +0000, Victor Porton via
 What of the two you would recommend?
Use: immutable str = "..."; in module-global scope. Or if this is inside a function, static immutable str = "..."; This places it in the data section of the object file and elides the extra pointer/size pair of `str` if it were mutable.
I haven't got what is your argument pro `immutable str` and so against enum.
Jan 16
prev sibling next sibling parent reply Johannes Loher <johannes.loher fg4f.de> writes:
On Wednesday, 16 January 2019 at 18:50:51 UTC, H. S. Teoh wrote:
 Also, you may have no choice but to use an enum if `str` is 
 referenced by compile-time code, since static globals would not 
 be readable at compile-time.
They are, if they are declared immutable (which is no problem if using enum would also be ok). The following program outputs "0" during compilation: ``` static immutable i = 0; static if (i == 0) { pragma(msg, i); } void main() { } ```
Jan 16
parent Johannes Loher <johannes.loher fg4f.de> writes:
On Wednesday, 16 January 2019 at 19:06:18 UTC, Johannes Loher 
wrote:
 On Wednesday, 16 January 2019 at 18:50:51 UTC, H. S. Teoh wrote:
 Also, you may have no choice but to use an enum if `str` is 
 referenced by compile-time code, since static globals would 
 not be readable at compile-time.
They are, if they are declared immutable (which is no problem if using enum would also be ok). The following program outputs "0" during compilation: ``` static immutable i = 0; static if (i == 0) { pragma(msg, i); } void main() { } ```
Actually in this case, it can also simply be `immutable i = 0;`, the `static` keyword doesn't do anything in this case. This also works and also prints "0" during compilation: ``` void main() { static immutable i = 0; static if (i == 0) { pragma(msg, i); } } ``` The argument for using `static immutable` (or `immutable` at module level) is that unlike enum, it will only ever use one instance. It will not allocate several times. As was mentioned before, this is also true for `enum` when used with strings, but strings are a special case. For other array types (and associative array types), a new instance is allocated whenever the `enum` is used.
Jan 16
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 1/16/19 1:50 PM, H. S. Teoh wrote:
 Also, you may have no choice but to use an enum if
 `str` is referenced by compile-time code, since static globals would not
 be readable at compile-time.
Not sure what you mean, this should work. Only immutable globals that aren't initialized until runtime can't be used. e.g.: immutable string s; immutable string s2 = "abc"; shared static this() { s = "abc"; } pragma(msg, s); // error pragma(msg, s2); // OK -Steve
Jan 16
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, Jan 16, 2019 at 02:10:02PM -0500, Steven Schveighoffer via
Digitalmars-d wrote:
 On 1/16/19 1:50 PM, H. S. Teoh wrote:
 Also, you may have no choice but to use an enum if `str` is
 referenced by compile-time code, since static globals would not be
 readable at compile-time.
Not sure what you mean, this should work. Only immutable globals that aren't initialized until runtime can't be used.
Ahh, I see. I stand corrected. :-) T -- Verbing weirds language. -- Calvin (& Hobbes)
Jan 16
prev sibling next sibling parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/16/2019 10:21 AM, Victor Porton wrote:
 What is more space efficient:
 
 enum str = "safjkdfjksdlfkdsj";
 
 or
 
 string str = "safjkdfjksdlfkdsj";
 
 ?
You can find this out by: dmd -c test.d obj2asm test.obj Also, enum s = "hello"; size_t i = s.length; The string "hello" does not appear in the object file. immutable string s = "hello"; size_t i = s.length; The string "hello" does appear in the object file. immutable string s = "hello"; immutable string t = "hello"; The string "hello" appears only once in the object file.
Jan 16
prev sibling parent reply Mathias Lang <pro.mathias.lang gmail.com> writes:
On Wednesday, 16 January 2019 at 18:21:29 UTC, Victor Porton 
wrote:
 What is more space efficient:

 enum str = "safjkdfjksdlfkdsj";

 or

 string str = "safjkdfjksdlfkdsj";

 ?

 with the first code fragment, won't the string be re-created 
 and re-inserted into the object file one time whenever str is 
 used, rather than once?

 What of the two you would recommend?
I've seen people using mostly `enum` over `(static) immutable`, but... When we ported our code from D1 to D2 in Sociomantic, we created a small fixup tool (https://github.com/sociomantic-tsunami/d1to2fix) and one of its job was to convert D1-style manifest constant (`const X = initializer;`) into "D2 style" (`enum X = initializer;`). And allocations started to show up where they would not before. After we got a rather complete and insightful explanation of the difference between `enum` and `static immutable` by Don Clugston, we switched to `static immutable` (almost) everywhere, and that was definitely a win. You can see `enum` as a `#define`. It will get "copy-pasted" everywhere, and thus, it's a rvalue (you can't take the address of an enum). On the other hand, `static immutable` are actual variable that will live in the binary. They are a symbol you can take the address of. They behave exactly like you would want a manifest constant to behave. There is only one corner case I know of where enum is more practical, it's the following code: ```D static immutable INITIALIZER = [1, 2, 3, 4]; // Does not work because it tries to do immutable -> mutable enum INITIALIZER = [1, 2, 3, 4]; // Works because every time it is used, it allocates a new array void foo (int[] value = INITIALIZER) { ... } ``` That being said, the DMD frontend is clever enough to avoid pointless allocations in the most obvious cases. So for example an array literal indexed by a compile-time known index will not allocate (`enum ARR = [0, 1, 2]; int i = ARR[0];`). However, if the index is not known at compile time, it will allocate every time with `enum`, never with `static immutable`. TL;DR: Use `static immutable` by default, `enum` if you want a `#define`.
Jan 16
parent reply Walter Bright <newshound2 digitalmars.com> writes:
That's true for arrays, but for strings the compiler will emit only one string, 
and everything else will refer to that.
Jan 16
parent reply Meta <jared771 gmail.com> writes:
On Thursday, 17 January 2019 at 06:00:09 UTC, Walter Bright wrote:
 That's true for arrays, but for strings the compiler will emit 
 only one string, and everything else will refer to that.
While we have your ear, Walter, what about an enum that is an array of strings? Will an enum array of strings with length N behave the same way as a single string and only emit those N strings once, or will a new array be allocated each time the enum is used?
Jan 17
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, Jan 17, 2019 at 03:16:16PM +0000, Meta via Digitalmars-d wrote:
 On Thursday, 17 January 2019 at 06:00:09 UTC, Walter Bright wrote:
 That's true for arrays, but for strings the compiler will emit only
 one string, and everything else will refer to that.
While we have your ear, Walter, what about an enum that is an array of strings? Will an enum array of strings with length N behave the same way as a single string and only emit those N strings once, or will a new array be allocated each time the enum is used?
You could just check the disassembly yourself. On my system, I found that the strings themselves are only stored once. But the outer array is allocated and repopulated each time, each time by a call to a druntime function _d_arrayliteralTX. T -- Genius may have its limitations, but stupidity is not thus handicapped. -- Elbert Hubbard
Jan 17
parent Walter Bright <newshound2 digitalmars.com> writes:
On 1/17/2019 7:32 AM, H. S. Teoh wrote:
 You could just check the disassembly yourself.
It's a good practice to follow. I don't always remember what it does exactly, as it changes over time, and multiple people have contributed to it. I check the assembler output myself just to be sure.
Jan 17