www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Testing implicit conversion to template instance with is() expression

reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
Should this work?

     struct V(string s) {
     }

     struct S(int U) {
         V!"xyz" x;
         alias x this;
     }

     void main() {
         S!10 a;
         static assert(is(a : V!Args, Args...));
     }

With DMD Git master, the static assert() fails. Should it? Am I 
doing something wrong? How can I test whether something is 
implicitly convertible to any instance of a particular template?
Mar 15 2015
parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 03/15/2015 08:47 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= 
<schuetzm gmx.net>" wrote:

 Should this work?

      struct V(string s) {
      }

      struct S(int U) {
          V!"xyz" x;
          alias x this;
      }

      void main() {
          S!10 a;
          static assert(is(a : V!Args, Args...));
      }

 With DMD Git master, the static assert() fails. Should it? Am I doing
 something wrong? How can I test whether something is implicitly
 convertible to any instance of a particular template?
There is no way other than checking for compile-time duck typing (see the implementations of isInputRange and others). One reason is that the compiler does not have the concept of "an instance of a template". Templates are for code generation and only the end-result (i.e. S!10) lives as a concept when compiling. Ali
Mar 15 2015
parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Sunday, 15 March 2015 at 16:44:14 UTC, Ali Çehreli wrote:
 On 03/15/2015 08:47 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= 
 <schuetzm gmx.net>" wrote:

 Should this work?

      struct V(string s) {
      }

      struct S(int U) {
          V!"xyz" x;
          alias x this;
      }

      void main() {
          S!10 a;
          static assert(is(a : V!Args, Args...));
      }

 With DMD Git master, the static assert() fails. Should it? Am
I doing
 something wrong? How can I test whether something is
implicitly
 convertible to any instance of a particular template?
There is no way other than checking for compile-time duck typing (see the implementations of isInputRange and others). One reason is that the compiler does not have the concept of "an instance of a template". Templates are for code generation and only the end-result (i.e. S!10) lives as a concept when compiling.
The code contained a small mistake, I forgot a `typeof()`: // static assert(is(a : V!Args, Args...)); // should be: static assert(is(typeof(a) : V!Args, Args...)); This still fails, but it works when I change it to: static assert(is(typeof(a) : S!Args, Args...)); This means I can indeed test whether something _is_ an instance of a template. It just doesn't take the `alias this` into account. So I guess that's a bug?
Mar 15 2015
parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Sunday, 15 March 2015 at 16:53:34 UTC, Marc Schütz wrote:
 On Sunday, 15 March 2015 at 16:44:14 UTC, Ali Çehreli wrote:
 On 03/15/2015 08:47 AM, "Marc =?UTF-8?B?U2Now7x0eiI=?= 
 <schuetzm gmx.net>" wrote:

 Should this work?

     struct V(string s) {
     }

     struct S(int U) {
         V!"xyz" x;
         alias x this;
     }

     void main() {
         S!10 a;
         static assert(is(a : V!Args, Args...));
     }

 With DMD Git master, the static assert() fails. Should it? Am
I doing
 something wrong? How can I test whether something is
implicitly
 convertible to any instance of a particular template?
There is no way other than checking for compile-time duck typing (see the implementations of isInputRange and others). One reason is that the compiler does not have the concept of "an instance of a template". Templates are for code generation and only the end-result (i.e. S!10) lives as a concept when compiling.
The code contained a small mistake, I forgot a `typeof()`: // static assert(is(a : V!Args, Args...)); // should be: static assert(is(typeof(a) : V!Args, Args...)); This still fails, but it works when I change it to: static assert(is(typeof(a) : S!Args, Args...)); This means I can indeed test whether something _is_ an instance of a template. It just doesn't take the `alias this` into account. So I guess that's a bug?
Ok, now I'm pretty sure: class V(string s) { } class S(int U) : V!"xyz" { } void main() { S!10 a; static if(is(typeof(a) : V!Args, Args...)) pragma(msg, Args); } This works, and it even correctly infers `Args` to be `tuple("xyz")`. As `alias this` is supposed to be interchangeable with subtyping, it must be a bug.
Mar 15 2015
parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
https://issues.dlang.org/show_bug.cgi?id=14286

In the meantime, does someone know of a suitable workaround?
Mar 15 2015
parent reply "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Sunday, 15 March 2015 at 17:03:42 UTC, Marc Schütz wrote:
 https://issues.dlang.org/show_bug.cgi?id=14286

 In the meantime, does someone know of a suitable workaround?
I found the following workaround. Not beautiful, but it works: enum isValue(alias T) = __traits(compiles, typeof(T)); template isConvertibleToInstanceOf(alias From, alias To) if(isValue!From) { enum isConvertibleToInstanceOf = isConvertibleToInstanceOf!(typeof(From), To); } template isConvertibleToInstanceOf(From, alias To) if(!is(From == struct) && !is(From == class) && !is(From == interface)) { enum isConvertibleToInstanceOf = false; } template isConvertibleToInstanceOf(From, alias To) if(is(From == struct) || is(From == class) || is(From == interface)) { // workaround for https://issues.dlang.org/show_bug.cgi?id=14286 import std.typetuple : anySatisfy; enum aliasThisConvertible(string name) = isConvertibleToInstanceOf!(mixin("typeof(From." ~ name ~ ")"), To); enum isConvertibleToInstanceOf = anySatisfy!(aliasThisConvertible, __traits(getAliasThis, From)) || is(From : To!Args, Args...); }
Mar 15 2015
parent reply "Nicolas Sicard" <dransic gmail.com> writes:
On Sunday, 15 March 2015 at 18:33:32 UTC, Marc Schütz wrote:
 On Sunday, 15 March 2015 at 17:03:42 UTC, Marc Schütz wrote:
 https://issues.dlang.org/show_bug.cgi?id=14286

 In the meantime, does someone know of a suitable workaround?
I found the following workaround. Not beautiful, but it works: enum isValue(alias T) = __traits(compiles, typeof(T)); template isConvertibleToInstanceOf(alias From, alias To) if(isValue!From) { enum isConvertibleToInstanceOf = isConvertibleToInstanceOf!(typeof(From), To); } template isConvertibleToInstanceOf(From, alias To) if(!is(From == struct) && !is(From == class) && !is(From == interface)) { enum isConvertibleToInstanceOf = false; } template isConvertibleToInstanceOf(From, alias To) if(is(From == struct) || is(From == class) || is(From == interface)) { // workaround for https://issues.dlang.org/show_bug.cgi?id=14286 import std.typetuple : anySatisfy; enum aliasThisConvertible(string name) = isConvertibleToInstanceOf!(mixin("typeof(From." ~ name ~ ")"), To); enum isConvertibleToInstanceOf = anySatisfy!(aliasThisConvertible, __traits(getAliasThis, From)) || is(From : To!Args, Args...); }
It works for your previous code example: static assert(isConvertibleToInstanceOf!(S!10, V)); // OK But this also works: static assert(!isConvertibleToInstanceOf!(S!10, V!"abc")); // OK Can be reduced to: struct Foo(int i) {} alias Foo1 = Foo!1; static assert(is(Foo!2 == Foo1!T, T...)); // OK I think it's another bug.
Mar 15 2015
parent "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> writes:
On Sunday, 15 March 2015 at 18:53:33 UTC, Nicolas Sicard wrote:
 Can be reduced to:
 struct Foo(int i) {}
 alias Foo1 = Foo!1;
 static assert(is(Foo!2 == Foo1!T, T...)); // OK

 I think it's another bug.
Right, I've filed another report: https://issues.dlang.org/show_bug.cgi?id=14290
Mar 15 2015