Jump to page: 1 2 3
Thread overview
best/proper way to declare constants ?
Aug 05, 2021
someone
Aug 05, 2021
H. S. Teoh
Aug 05, 2021
someone
Aug 05, 2021
H. S. Teoh
Aug 05, 2021
someone
Aug 05, 2021
someone
Aug 05, 2021
H. S. Teoh
Aug 05, 2021
someone
Aug 05, 2021
jfondren
Aug 05, 2021
someone
Aug 05, 2021
H. S. Teoh
Aug 06, 2021
someone
Aug 06, 2021
Ali Çehreli
Aug 06, 2021
someone
Aug 06, 2021
someone
Aug 06, 2021
someone
Aug 05, 2021
someone
Aug 05, 2021
someone
Aug 06, 2021
norm
August 05, 2021

What are the pros/cons of the following approaches ?

/// first day with D:

public const dstring gstrWhatever = "...";

/// next:

public immutable dstring gstrWhatever = "...";

/// next:

public immutable dstring gstrWhatever;

this() {

   gstrWhatever = "...";

}

/// next (manifest-constant):

public immutable enum gstrWhatever = "...";

Are manifest-constants the proper way to go ?

In [http://ddili.org/ders/d.en/enum.html] Ali says:

"We have discussed that it is important to avoid magic constants and instead to take advantage of the enum feature ..."

enum fileName = "list.txt";

"Such constants are rvalues and they are called manifest constants."

"It is possible to create manifest constants of arrays and associative arrays as well. However, as we will see later in the Immutability chapter, enum arrays and associative arrays may have hidden costs."

August 04, 2021
On Thu, Aug 05, 2021 at 12:47:06AM +0000, someone via Digitalmars-d-learn wrote:
> What are the pros/cons of the following approaches ?

1) If the constant is a POD (int, float, etc.), use:

	enum myValue = ...;

2) If the constant is a string or some other array:

	static immutable string myString = "...";
	static immutable Data[] myData = [ ... ];

Unless you have a specific reason to, avoid using `enum` with string and array literals, because they will trigger a memory allocation *at every single reference to them*, which is probably not what you want.

	enum myArray = [ 1, 2, 3 ];
	...
	int[] data = myArray;	// allocates a new array
	int[] data2 = myArray;	// allocates another array

	// they are separate arrays with the same contents
	assert(data !is data2);
	assert(data == data2);

	// allocates a temporary array, does the comparison, then
	// discards the temporary
	if (data == myArray) ...

	foreach (i; 0 .. 10) {
		int[] input = getUserInput(...);

		// allocates a new array at every single loop iteration
		if (input == myArray) { ... }
	}

Don't do this. Use static immutable for arrays and strings, use enum only for PODs.


T

-- 
It's amazing how careful choice of punctuation can leave you hanging:
August 05, 2021
On Thursday, 5 August 2021 at 01:14:26 UTC, H. S. Teoh wrote:
> 1) If the constant is a POD (int, float, etc.), use:
>
> 	enum myValue = ...;

crystal-clear.

> 2) If the constant is a string or some other array:
>
> 	static immutable string myString = "...";

crystal-clear.

> 2) If the constant is a string or some other array:
>
> 	static immutable Data[] myData = [ ... ];
>
> Unless you have a specific reason to, avoid using `enum` with string and array literals, because they will trigger a memory allocation *at every single reference to them*, which is probably not what you want.
>
> 	enum myArray = [ 1, 2, 3 ];
> 	...
> 	int[] data = myArray;	// allocates a new array
> 	int[] data2 = myArray;	// allocates another array
>
> 	// they are separate arrays with the same contents
> 	assert(data !is data2);
> 	assert(data == data2);
>
> 	// allocates a temporary array, does the comparison, then
> 	// discards the temporary
> 	if (data == myArray) ...
>
> 	foreach (i; 0 .. 10) {
> 		int[] input = getUserInput(...);
>
> 		// allocates a new array at every single loop iteration
> 		if (input == myArray) { ... }
> 	}

What happens in the following case ?

public immutable enum gudtLocations = [
   r"BUE"d : structureLocation(r"arg"d, r"Buenos Aires"d, r"ART"d),
   r"GRU"d : structureLocation(r"bra"d, r"São Paulo"d, r"BRT"d),
   r"HHN"d : structureLocation(r"deu"d, r"Frankfurt am Main"d, r"CET"d),
   r"LHR"d : structureLocation(r"gbr"d, r"London"d, r"UTC"d),
   r"NYC"d : structureLocation(r"usa"d, r"New York"d, r"EST"d)
   ];

This is something that I also need at compilation time.

Throwing away the enum and recoding as following:

static immutable structureLocation[stringUTF32] gudtLocations = [
   r"BUE"d : structureLocation(r"arg"d, r"Buenos Aires"d, r"ART"d),
   r"GRU"d : structureLocation(r"bra"d, r"São Paulo"d, r"BRT"d),
   r"HHN"d : structureLocation(r"deu"d, r"Frankfurt am Main"d, r"CET"d),
   r"LHR"d : structureLocation(r"gbr"d, r"London"d, r"UTC"d),
   r"NYC"d : structureLocation(r"usa"d, r"New York"d, r"EST"d)
   ];

gives me:

Error: non-constant expression `["BUE"d:structureLocation(true, "arg"d, null, "Buenos Aires"d, "ART"d), "GRU"d:structureLocation(true, "bra"d, null, "S\xe3o Paulo"d, "BRT"d), "HHN"d:structureLocation(true, "deu"d, null, "Frankfurt am Main"d, "CET"d), "LHR"d:structureLocation(true, "gbr"d, null, "London"d, "UTC"d), "NYC"d:structureLocation(true, "usa"d, null, "New York"d, "EST"d)]`

> Don't do this. Use static immutable for arrays and strings, use enum only for PODs.

crystal-clear.
August 04, 2021

On 8/4/21 9:14 PM, H. S. Teoh wrote:

>

Unless you have a specific reason to, avoid using enum with string and
array literals, because they will trigger a memory allocation at every
single reference to them
, which is probably not what you want.

Just want to chime in and say this is NOT true for string literals. Only array literals.

-Steve

August 05, 2021

On Thursday, 5 August 2021 at 02:06:13 UTC, Steven Schveighoffer wrote:

>

On 8/4/21 9:14 PM, H. S. Teoh wrote:

>

Unless you have a specific reason to, avoid using enum with string and
array literals, because they will trigger a memory allocation at every
single reference to them
, which is probably not what you want.

Just want to chime in and say this is NOT true for string literals. Only array literals.

OK. Not for arrays then ... but for string literals ? which one then ?

static immutable string fileName = "list.txt";

vs

enum fileName = "list.txt";

>

-Steve

August 04, 2021

On 8/4/21 10:27 PM, someone wrote:

>

On Thursday, 5 August 2021 at 02:06:13 UTC, Steven Schveighoffer wrote:

>

On 8/4/21 9:14 PM, H. S. Teoh wrote:

>

Unless you have a specific reason to, avoid using enum with string and
array literals, because they will trigger a memory allocation at every
single reference to them
, which is probably not what you want.

Just want to chime in and say this is NOT true for string literals. Only array literals.

OK. Not for arrays then ... but for string literals ? which one then ?

static immutable string fileName = "list.txt";

vs

enum fileName = "list.txt";

The main difference between enums and static immutable is that the latter has an address at runtime. You cannot take the address of an enum (which only exists at compile time). You can think of an enum to be a substitute for typing out that expression directly. For array literals, this means, do a new allocation.

However, a string literal is a special case of an array which does NOT allocate -- it puts the string data into the read-only segment, and the literal references that data, which is why string enums do not allocate when used.

So the answer is, depends on what you are going to do with the data. There are use cases for both. If you just want an alias to represent the literal, I'd say use enum, it should work fine.

Off the top of my head for strings:

  1. A static immutable loses its "C string compatibility", whereas an enum does not.
  2. A static immutable can be passed as an alias to a template, and the template mangle only involves the variable name, whereas passing an enum will use the string contents for the template mangle. This can be a huge difference for symbol sizes.
  3. A static immutable can be used as an argument to a reference parameter, an enum cannot.
  4. A static immutable will consume space in your executable even if never used, an enum will not.

-Steve

August 04, 2021
On Thu, Aug 05, 2021 at 01:39:42AM +0000, someone via Digitalmars-d-learn wrote: [...]
> What happens in the following case ?
> 
> public immutable enum gudtLocations = [
>    r"BUE"d : structureLocation(r"arg"d, r"Buenos Aires"d, r"ART"d),
>    r"GRU"d : structureLocation(r"bra"d, r"São Paulo"d, r"BRT"d),
>    r"HHN"d : structureLocation(r"deu"d, r"Frankfurt am Main"d, r"CET"d),
>    r"LHR"d : structureLocation(r"gbr"d, r"London"d, r"UTC"d),
>    r"NYC"d : structureLocation(r"usa"d, r"New York"d, r"EST"d)
>    ];
> 
> This is something that I also need at compilation time.
[...]

If you need a constant array value both at compile-time and runtime, one way to do it is to declare an enum that is used only by compile-time code, and the same enum is used once to declare the runtime static immutable.

Example:

	enum ctValue = [ "my", "data", "here", ... ];

	// Initialize this once with ctValue.
	static immutable string[] rtValue = ctValue;

	if (ctfe) {
		// Compile-time: use ctValue
		foreach (value; ctValue) {
			...
		}
	} else {
		// Runtime: use rtValue instead
		foreach (value; rtValue) {
			...
		}
	}

Just be sure you don't use ctValue during runtime, otherwise it will incur an allocation per use.


T

-- 
What did the alien say to Schubert? "Take me to your lieder."
August 05, 2021

On Thursday, 5 August 2021 at 02:43:09 UTC, Steven Schveighoffer wrote:

>

The main difference between enums and static immutable is that the latter has an address at runtime.

This. Gotcha.

>

So the answer is, depends on what you are going to do with the data. There are use cases for both. If you just want an alias to represent the literal, I'd say use enum, it should work fine.

ACK. Now I understand the difference.

Thanks a lot for your detailed reply Steve !

One of the things D has as a plus is ... the community; very welcome indeed :)

August 05, 2021
On Thursday, 5 August 2021 at 03:20:17 UTC, H. S. Teoh wrote:
> On Thu, Aug 05, 2021 at 01:39:42AM +0000, someone via Digitalmars-d-learn wrote: [...]
>> What happens in the following case ?
>> 
>> public immutable enum gudtLocations = [
>>    r"BUE"d : structureLocation(r"arg"d, r"Buenos Aires"d, r"ART"d),
>>    r"GRU"d : structureLocation(r"bra"d, r"São Paulo"d, r"BRT"d),
>>    r"HHN"d : structureLocation(r"deu"d, r"Frankfurt am Main"d, r"CET"d),
>>    r"LHR"d : structureLocation(r"gbr"d, r"London"d, r"UTC"d),
>>    r"NYC"d : structureLocation(r"usa"d, r"New York"d, r"EST"d)
>>    ];
>> 
>> This is something that I also need at compilation time.
> [...]
>
> If you need a constant array value both at compile-time and runtime, one way to do it is to declare an enum that is used only by compile-time code, and the same enum is used once to declare the runtime static immutable.
>
> Example:
>
> 	enum ctValue = [ "my", "data", "here", ... ];
>
> 	// Initialize this once with ctValue.
> 	static immutable string[] rtValue = ctValue;
>
> 	if (ctfe) {
> 		// Compile-time: use ctValue
> 		foreach (value; ctValue) {
> 			...
> 		}
> 	} else {
> 		// Runtime: use rtValue instead
> 		foreach (value; rtValue) {
> 			...
> 		}
> 	}

Nice and fine.

Problem is that in your example ctValue is int by default; e: my=0, data=1, etc

And what I need at compiled time are strings to build/name classes and the like.

I need a compile-time enum (or whatever) that gets me "NYSE" "NASDAQ" etc AND that I can use with static foreach {}

My code is far from right but it actually does the job right now:

public enum gudtLocations = [
   r"BUE"d : structureLocation(r"arg"d, r"Buenos Aires"d, r"ART"d),
   r"GRU"d : structureLocation(r"bra"d, r"São Paulo"d, r"BRT"d),
   r"HHN"d : structureLocation(r"deu"d, r"Frankfurt am Main"d, r"CET"d),
   r"LHR"d : structureLocation(r"gbr"d, r"London"d, r"UTC"d),
   r"NYC"d : structureLocation(r"usa"d, r"New York"d, r"EST"d)
   ];

public enum gudtExchanges = [
   r"B3"d     : structureExchange(gudtLocations[r"GRU"d], r"B3"d, r"B3 formerly Bolsa de Valores de São Paulo (aka BOVESPA)"d, r"BRL"d),
   r"BCBA"d   : structureExchange(gudtLocations[r"BUE"d], r"BCBA"d, r"Bolsa de Comercio de Buenos Aires"d, r"ARS"d),
   r"LSE"d    : structureExchange(gudtLocations[r"LHR"d], r"LSE"d, r"London Stock Exchange"d, r"GBP"d),
   r"NASDAQ"d : structureExchange(gudtLocations[r"NYC"d], r"NASDAQ"d, r"National Association of Securities Dealers Automated Quotations"d, r"USD"d),
   r"NYSE"d   : structureExchange(gudtLocations[r"NYC"d], r"NYSE"d, r"New York Stock Exchange"d, r"USD"d),
   r"XETRA"d  : structureExchange(gudtLocations[r"HHN"d], r"XETRA"d, r"Deutsche Börse"d, r"EUR"d)
   ]; /// byKeyValue is not available at compile‐time; hence the redundancy of IDs

And of course now I fully understand why it is not optimal at all.

> Just be sure you don't use ctValue during runtime, otherwise it will incur an allocation per use.
>
>
> T


August 05, 2021

On 8/4/21 11:20 PM, H. S. Teoh wrote:

>

On Thu, Aug 05, 2021 at 01:39:42AM +0000, someone via Digitalmars-d-learn wrote:
[...]

>

What happens in the following case ?

public immutable enum gudtLocations = [
r"BUE"d : structureLocation(r"arg"d, r"Buenos Aires"d, r"ART"d),
r"GRU"d : structureLocation(r"bra"d, r"São Paulo"d, r"BRT"d),
r"HHN"d : structureLocation(r"deu"d, r"Frankfurt am Main"d, r"CET"d),
r"LHR"d : structureLocation(r"gbr"d, r"London"d, r"UTC"d),
r"NYC"d : structureLocation(r"usa"d, r"New York"d, r"EST"d)
];

This is something that I also need at compilation time.
[...]

If you need a constant array value both at compile-time and runtime, one
way to do it is to declare an enum that is used only by compile-time
code, and the same enum is used once to declare the runtime static
immutable.

A static immutable array is usable at compile time. No need for the enum.

>

Example:

enum ctValue = [ "my", "data", "here", ... ];

// Initialize this once with ctValue.
static immutable string[] rtValue = ctValue;

if (ctfe) {

if(__ctfe) {

>
  // Compile-time: use ctValue
  foreach (value; ctValue) {
  	...
  }

} else {
// Runtime: use rtValue instead
foreach (value; rtValue) {
...
}
}

Just be sure you don't use ctValue during runtime, otherwise it will
incur an allocation per use.

H.S. Teoh, I know you know better than this ;) None of this is necessary, you just need rtValue for both runtime and CTFE (and compile time parameters)!

Now, the original question is about associative arrays, which are a different animal. Those, you actually have to initialize using a static constructor, and does indeed need both an enum and a static immutable, as CTFE currently does not understand runtime AAs. This is a huge issue since you do need silly things like the if(__ctfe) statement you wrote, and keep an enum handy for those cases which is identical to the static immutable. We really need to fix this.

-Steve

« First   ‹ Prev
1 2 3