www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Manipulating variables without evaluating them

reply Dadoum <dadoum protonmail.com> writes:
Hello,

I am currently making a wrapper around libplist in D, and to get 
a good syntax I first thought about making a `pl` function with 
bunch of overloads allowing to convert strings, integers, 
booleans into the corresponding `Plist` type. It is working but 
the problem here is that associative array literals are not 
preserving order (they are immediately hashed, and so all the 
keys are in a random order).

To overcome that, I create a template `plistDict` as such:

```d
template plistDict(alias U) {
     PlistDict pl() {
         auto dict = new PlistDict();
         static foreach (elem; dict) {
             dict[elem.key] = elem.value;
         }
         return dict;
     }
}
```

The `static foreach` ensures everything is running at compile 
time, and so no hash should mess with the keys. But the problem 
here is that it tries to evaluate at compile time the value of 
each entry in the associative array (what it can't do since it's 
a wrapper around a C library!).

The same kind of issue can be encountered in this small code 
snippet:

```d
string crashingFunction() {
	assert(!__ctfe);
	return "OK";
}

template macroLikeTemplate(alias U) {
	string macroLikeTemplate() {
		return "" ~ U;
	}
}

void main()
{
	macroLikeTemplate!(crashingFunction());
}

```

Here, the function is evaluated before the element is passed to 
the template, and is failing (here because of an assert, but we 
can imagine something that would fail only at compile-time like a 
C call), while the substitution could just work fine if it wasn't 
evaluated before hand.

Is there any way to make this work?
May 07 2023
next sibling parent Dadoum <dadoum protonmail.com> writes:
On Sunday, 7 May 2023 at 17:11:52 UTC, Dadoum wrote:
 ```d
 string crashingFunction() {
 	assert(!__ctfe);
 	return "OK";
 }

 template macroLikeTemplate(alias U) {
 	string macroLikeTemplate() {
 		return "" ~ U;
 	}
 }

 void main()
 {
 	macroLikeTemplate!(crashingFunction());
 }

 ```
By the way, this snippet could work if I just made `macroLikeTemplate` a regular function. But in the case I presented precisely, I have to iterate at compile time through the elements, otherwise the elements would be put in the wrong order, thus it can't be a function at runtime.
May 07 2023
prev sibling next sibling parent ag0aep6g <anonymous example.com> writes:
On 07.05.23 19:11, Dadoum wrote:
 To overcome that, I create a template `plistDict` as such:
 
 ```d
 template plistDict(alias U) {
      PlistDict pl() {
          auto dict = new PlistDict();
          static foreach (elem; dict) {
              dict[elem.key] = elem.value;
          }
          return dict;
      }
 }
 ```
1. The `static foreach` can't work. `dict` is a run-time value. You can't iterate it at compile time like that. 2. `U` is unused. 3. You're just assigning everything from `dict` back to `dict`. Did you maybe mean `static foreach (elem; U)`?
 The `static foreach` ensures everything is running at compile time, and 
 so no hash should mess with the keys. But the problem here is that it 
 tries to evaluate at compile time the value of each entry in the 
 associative array (what it can't do since it's a wrapper around a C 
 library!).
Hard to tell what's going on because your code is missing crucial parts: what is `PlistDict` and how are you instantiating `plistDict`?
 The same kind of issue can be encountered in this small code snippet:
 
 ```d
 string crashingFunction() {
      assert(!__ctfe);
      return "OK";
 }
 
 template macroLikeTemplate(alias U) {
      string macroLikeTemplate() {
          return "" ~ U;
      }
 }
 
 void main()
 {
      macroLikeTemplate!(crashingFunction());
 }
 
 ```
This one is a simple fix. Just don't call `crashingFunction` at the instantiation site: macroLikeTemplate!(crashingFunction);
May 07 2023
prev sibling parent reply Salih Dincer <salihdb hotmail.com> writes:
On Sunday, 7 May 2023 at 17:11:52 UTC, Dadoum wrote:
 Hello,

 I am currently making a wrapper around libplist in D, and to 
 get a good syntax I first thought about making a `pl` function 
 with bunch of overloads allowing to convert strings, integers, 
 booleans into the corresponding `Plist` type. It is working but 
 the problem here is that associative array literals are not 
 preserving order (they are immediately hashed, and so all the 
 keys are in a random order).
It's hard to figure out what you want but there are errors in your code. This works: ```d auto plistDict(alias AA)() { auto dict = new string[AA.length]; foreach (key, value; AA) { dict[key] = value; } return dict; } import std.stdio; void main() { auto plist = plistDict!([0: "zero", 1: "one", 2: "two"]); plist.writeln; // ["zero", "one", "two"] } ``` And yes, the data is not converted at compile time. SDB 79
May 08 2023
parent reply Dadoum <dadoum protonmail.com> writes:
On Monday, 8 May 2023 at 11:06:59 UTC, Salih Dincer wrote:
 On Sunday, 7 May 2023 at 17:11:52 UTC, Dadoum wrote:
 Hello,

 I am currently making a wrapper around libplist in D, and to 
 get a good syntax I first thought about making a `pl` function 
 with bunch of overloads allowing to convert strings, integers, 
 booleans into the corresponding `Plist` type. It is working 
 but the problem here is that associative array literals are 
 not preserving order (they are immediately hashed, and so all 
 the keys are in a random order).
It's hard to figure out what you want but there are errors in your code. This works: ```d auto plistDict(alias AA)() { auto dict = new string[AA.length]; foreach (key, value; AA) { dict[key] = value; } return dict; } import std.stdio; void main() { auto plist = plistDict!([0: "zero", 1: "one", 2: "two"]); plist.writeln; // ["zero", "one", "two"] } ``` And yes, the data is not converted at compile time. SDB 79
I should have worded my question differently. The problem here is that the values are not constant at compile time. It should be emulated with ```d auto plistDict(alias AA)() { auto dict = new string[AA.length]; foreach (key, value; AA) { dict[key] = value; } return dict; } import std.stdio; extern(C) void functionThatCannotBeEvaluatedAtCompileTime(); string conversionFunction(string val) { functionThatCannotBeEvaluatedAtCompileTime(); return val; } void main() { auto plist = plistDict!([ 0: "zero".conversionFunction, // Error: `functionThatCannotBeEvaluatedAtCompileTime` cannot be interpreted at compile time, because it has no available source code 1: "one".conversionFunction, 2: "two".conversionFunction, ]); plist.writeln; } ``` Here, it complains that the values cannot be evaluated since it has no source code. But I don't care about the source code here, I just want the code on the left to be executed at runtime, not evaluate it right at compilation. (and yeah in my first snippet I shouldn't iterate through the runtime dict but the compile time U, I made a mistake while compacting the code to post it here). Is there a way to use the associative array here at compile time while avoiding the evaluation of those keys?
May 08 2023
parent reply ag0aep6g <anonymous example.com> writes:
On Monday, 8 May 2023 at 11:42:44 UTC, Dadoum wrote:
 ```d
 auto plistDict(alias AA)()
 {
 	auto dict = new string[AA.length];
 	foreach (key, value; AA)
 	{
 		dict[key] = value;
 	}
 	return dict;
 }

 import std.stdio;

 extern(C) void functionThatCannotBeEvaluatedAtCompileTime();

 string conversionFunction(string val) {
     functionThatCannotBeEvaluatedAtCompileTime();
     return val;
 }

 void main()
 {
 	auto plist = plistDict!([
 		0: "zero".conversionFunction, // Error: 
 `functionThatCannotBeEvaluatedAtCompileTime` cannot be 
 interpreted at compile time, because it has no available source 
 code
 		1: "one".conversionFunction,
 		2: "two".conversionFunction,
 	]);
 	plist.writeln;
 }
 ```
[...]
 Is there a way to use the associative array here at compile 
 time while avoiding the evaluation of those keys?
Instead of passing values, pass functions that return the values: ```d auto plist = plistDict!([ 0: () => "zero".conversionFunction, 1: () => "one".conversionFunction, 2: () => "two".conversionFunction, ]); ``` And in `plistDict`, call the functions: ```d static foreach (key, fun; AA) { dict[key] = fun(); } ```
May 08 2023
parent Dadoum <dadoum protonmail.com> writes:
On Monday, 8 May 2023 at 12:01:35 UTC, ag0aep6g wrote:
 Instead of passing values, pass functions that return the 
 values:

 ```d
 	auto plist = plistDict!([
 		0: () => "zero".conversionFunction,
 		1: () => "one".conversionFunction,
 		2: () => "two".conversionFunction,
 	]);
 ```

 And in `plistDict`, call the functions:

 ```d
 	static foreach (key, fun; AA)
 	{
 		dict[key] = fun();
 	}
 ```
Thanks, I can get further now with this trick, but now it is complaining that some are delegate and other are function pointer because in the real situation this happens: ```d auto two = "two"; auto plist = plistDict!([ 0: () => "zero".conversionFunction, 1: () => "one".conversionFunction, 2: () => two.conversionFunction, ]); ```
May 08 2023