Thread overview
cannot interpret `cast(void)0` at compile time?
May 09, 2023
Dadoum
May 09, 2023
Salih Dincer
May 10, 2023
Dadoum
May 09, 2023

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)

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:

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:

			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

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)

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:

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 10, 2023

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:

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.