www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - cannot interpret `cast(void)0` at compile time?

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

I am making a libplist wrapper and I am currently writing a 
template to handle associative arrays and preserve the order of 
the keys in the conversion process. (I already talked a bit about 
that 
[here](https://forum.dlang.org/post/pxevvegnaqueprwrkfos forum.dlang.org))

I have `plistConvert` which is a function with a lot of overloads 
to convert any other type to its plist counterpart already, and I 
want to have a template `pl` to convert associative arrays to 
PlistDict. Here is the code:

```d
import std.stdio;
// stubs
class PlistDict {public void opIndexAssign(Plist element, string 
key) {writeln("key added: ", key);}}
class Plist {}
Plist plistConvert(T)(T val) => new Plist();

struct Wrapper {
	Plist delegate() val;
}

private Plist convertToPlist(alias U)() {
	return U.plistConvert();
}

// Preserves the order since associative arrays are hashed at 
runtime.
template pl(alias U) {
	static if (is(typeof(U): Wrapper[string])) {
		pragma(inline, true) PlistDict pl() {
			auto dict = new PlistDict();
			static foreach (k, v; U) {
				dict[k] = v.val();
			}
			return dict;
		}
	} else {
		static if (is(typeof(() => U.plistConvert()) == delegate)) {
			enum a = &convertToPlist!U;
			pragma(msg, a.stringof);
			enum pl = Wrapper(a);
		} else {
			enum pl = Wrapper(() => U.plistConvert());
		}
	}
}


void main() {
	auto runtimeValue = "tac";

	auto request = pl!([
		"constantKey": pl!"CONSTANT",
		"runtimeKey": pl!runtimeValue
	]);
}
```

Transforming the associative array into an associative array of 
delegates was a trick given by ag0aep6g in the other thread, but 
now I encounter a new error: `Error: cannot interpret 
`cast(void)0` at compile time`. No line given  or anything on DMD 
or LDC2 (on GDC it's giving a line in std.math.exponential???).

The problem lies here:

```d
			pragma(msg, a.stringof);
			enum pl = Wrapper(a);
```

because if Wrapper gets a random argument, it will work.

Also, giving a lambda to Wrapper as such: `enum pl = Wrapper(() 
=> U.plistConvert());` \
is also not working:
```
delegate `app.pl(alias U)` is a nested function and cannot be 
accessed from `app.pl!(["constantKey":Wrapper(() pure nothrow 
 safe => plistConvert("CONSTANT")), "runtimeKey":Wrapper(delegate 
() pure nothrow  safe => plistConvert(runtimeValue))]).pl
```

So I feel kind of blocked, I don't understand the first error and 
the second one seems to not be resoluble in this design.

Any thoughts?
May 09 2023
parent reply Salih Dincer <salihdb hotmail.com> writes:
On Tuesday, 9 May 2023 at 09:54:21 UTC, Dadoum wrote:
 Hello,

 I am making a libplist wrapper and I am currently writing a 
 template to handle associative arrays and preserve the order of 
 the keys in the conversion process. (I already talked a bit 
 about that 
 [here](https://forum.dlang.org/post/pxevvegnaqueprwrkfos forum.dlang.org))

 I have `plistConvert` which is a function with a lot of 
 overloads to convert any other type to its plist counterpart 
 already, and I want to have a template `pl` to convert 
 associative arrays to PlistDict.
To tell the truth, I'm a little confused. πŸ˜€ So I can't understand why we should use the delegate. Below I will share a similar example and it includes a wrapper (Bar), your class (PlistDict) and it works: ```d alias AA = Bar[string]; struct Bar // Wrapper { int value; } class Foo // PlistDict { void opIndexAssign(Bar element, string key) { import std.stdio; key.writeln(" added, value: ", element.value); } } template PL(alias R) // pl { static if(is(typeof(R) == AA)) { auto PL() { auto dict = new Foo(); static foreach (K, V; R) { dict[K] = V; } return dict; } } else static if(is(typeof(R) == int)) { enum PL = Bar(R); } else { enum PL = Bar(); } } void main() { enum two = 2; auto request = PL!( [ "one": PL!1, "two": PL!two, "zero": PL!"zero" ] ); } /* one added, value: 1 two added, value: 2 zero added, value: 0 */ ``` SDB 79
May 09 2023
parent Dadoum <dadoum protonmail.com> writes:
On Tuesday, 9 May 2023 at 23:27:07 UTC, Salih Dincer wrote:
 To tell the truth, I'm a little confused. πŸ˜€

 So I can't understand why we should use the delegate. Below I 
 will share a similar example and it includes a wrapper (Bar), 
 your class (PlistDict) and it works:


 ```d
 alias AA = Bar[string];

 struct Bar // Wrapper
 {
   int value;
 }

 class Foo // PlistDict
 {
   void opIndexAssign(Bar element, string key)
   {
     import std.stdio;
     key.writeln(" added, value: ", element.value);
   }
 }

 template PL(alias R) // pl
 {
   static if(is(typeof(R) == AA))
   {
     auto PL()
     {
       auto dict = new Foo();
       static foreach (K, V; R)
       {
         dict[K] = V;
       }
       return dict;
     }
   } else static if(is(typeof(R) == int)) {

     enum PL = Bar(R);

   } else {

     enum PL = Bar();

   }
 }

 void main()
 {
   enum two = 2;
   auto request = PL!(
        [
           "one": PL!1,
           "two": PL!two,
          "zero": PL!"zero"
        ]
   );
 } /*
 one added, value: 1
 two added, value: 2
 zero added, value: 0
 */
 ```
The problem I encounter happens because one of the variable is a run time one. Instead of `enum two`, there is `auto two`, and when we pass it in a template, we have to put in a delegate to prevent the compiler from evaluating it (it can’t because it’s runtime). But then the template has to create a delegate to a local variable and the scope where you can use it is very limited.
May 09 2023