www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - is(some template instantiation) is true, but the actual instantiation

reply Adrian Matoga <dlang.spam matoga.info> writes:
Code:

----
struct HasFoo { void foo() {} }

struct NoFoo {}

struct CallsFoo(T) {
	T t;
	void bar() { t.foo(); }
}

static assert(is(CallsFoo!HasFoo));
alias Bar = CallsFoo!HasFoo;

static assert(is(CallsFoo!NoFoo)); // (1)
//alias Baz = CallsFoo!NoFoo;      // (2)
----

This compiles, although I expected that (1) should fail.
Now try uncommenting (2) and it can't be compiled.

Why does `is(CallsFoo!NoFoo)` evaluate to true if 
`is(CallsFoo!NoFoo)` can't be instantiated?
Am I missing something about `is(T)` or is it a bug?
How can I reliably test if CallsFoo can be instantiated?
Jan 29
next sibling parent Basile B. <b2.temp gmx.com> writes:
On Friday, 29 January 2016 at 15:28:29 UTC, Adrian Matoga wrote:
 How can I reliably test if CallsFoo can be instantiated?
You can use a constraint to prevent invalid instantiation: struct HasFoo { void foo() {} } struct NoFoo {} struct CallsFoo(T) if (__traits(hasMember, T, "foo")) { T t; void bar() { t.foo(); } } static assert(is(CallsFoo!HasFoo)); static assert(!is(CallsFoo!NoFoo));
Jan 29
prev sibling parent reply Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/29/16 10:28 AM, Adrian Matoga wrote:
 Code:

 ----
 struct HasFoo { void foo() {} }

 struct NoFoo {}

 struct CallsFoo(T) {
      T t;
      void bar() { t.foo(); }
 }

 static assert(is(CallsFoo!HasFoo));
 alias Bar = CallsFoo!HasFoo;

 static assert(is(CallsFoo!NoFoo)); // (1)
 //alias Baz = CallsFoo!NoFoo;      // (2)
 ----

 This compiles, although I expected that (1) should fail.
 Now try uncommenting (2) and it can't be compiled.

 Why does `is(CallsFoo!NoFoo)` evaluate to true if `is(CallsFoo!NoFoo)`
 can't be instantiated?
 Am I missing something about `is(T)` or is it a bug?
 How can I reliably test if CallsFoo can be instantiated?
is(T) is supposed to be false if T is not a valid type. I would agree with you that the static assert should fail. -Steve
Jan 29
parent reply Adrian Matoga <dlang.spam matoga.info> writes:
On Friday, 29 January 2016 at 16:36:01 UTC, Steven Schveighoffer 
wrote:
 On 1/29/16 10:28 AM, Adrian Matoga wrote:
 Code:

 ----
 struct HasFoo { void foo() {} }

 struct NoFoo {}

 struct CallsFoo(T) {
      T t;
      void bar() { t.foo(); }
 }

 static assert(is(CallsFoo!HasFoo));
 alias Bar = CallsFoo!HasFoo;

 static assert(is(CallsFoo!NoFoo)); // (1)
 //alias Baz = CallsFoo!NoFoo;      // (2)
 ----

 This compiles, although I expected that (1) should fail.
 Now try uncommenting (2) and it can't be compiled.

 Why does `is(CallsFoo!NoFoo)` evaluate to true if 
 `is(CallsFoo!NoFoo)`
 can't be instantiated?
 Am I missing something about `is(T)` or is it a bug?
 How can I reliably test if CallsFoo can be instantiated?
is(T) is supposed to be false if T is not a valid type. I would agree with you that the static assert should fail. -Steve
Oh, there's more: // this should fail: static assert(is(CallsFoo!NoFoo)); // this should fail too: static assert(is(typeof({ alias Baz = CallsFoo!NoFoo; return Baz.init; }()))); // and this: static assert(__traits(compiles, { alias Baz = CallsFoo!NoFoo; return Baz.init; }())); // but only this fails: alias Baz = CallsFoo!NoFoo; https://issues.dlang.org/show_bug.cgi?id=15623
Jan 29
next sibling parent reply Basile B. <b2.temp gmx.com> writes:
On Friday, 29 January 2016 at 17:01:46 UTC, Adrian Matoga wrote:
 On Friday, 29 January 2016 at 16:36:01 UTC, Steven 
 Schveighoffer wrote:
 On 1/29/16 10:28 AM, Adrian Matoga wrote:
[...]
is(T) is supposed to be false if T is not a valid type. I would agree with you that the static assert should fail. -Steve
Oh, there's more: // this should fail: static assert(is(CallsFoo!NoFoo)); // this should fail too: static assert(is(typeof({ alias Baz = CallsFoo!NoFoo; return Baz.init; }()))); // and this: static assert(__traits(compiles, { alias Baz = CallsFoo!NoFoo; return Baz.init; }())); // but only this fails: alias Baz = CallsFoo!NoFoo; https://issues.dlang.org/show_bug.cgi?id=15623
Haven't you seen my answer about constraint ? If you put a constraint on your function template then invalid instantiations are rejected. I mean... this language feature is not just ornamental... What do you think constraints are used for otherwise ^^
Jan 29
next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 1/29/16 6:44 PM, Basile B. wrote:
 Haven't you seen my answer about constraint ?

 If you put a constraint on your function template then invalid
 instantiations are rejected. I mean... this language feature is not just
 ornamental...

 What do you think constraints are used for otherwise ^^
A constraint should not be necessary here. Constraints are useful when you have multiple templates that may match (without specializations), or you want to affect the way the compiler reports errors. Iff a template instantiation T compiles, then is(T) should evaluate to true. At least, that's my understanding. -Steve
Jan 29
prev sibling parent Adrian Matoga <dlang.spam matoga.info> writes:
On Friday, 29 January 2016 at 23:44:56 UTC, Basile B. wrote:
 Haven't you seen my answer about constraint ?

 If you put a constraint on your function template then invalid 
 instantiations are rejected. I mean... this language feature is 
 not just ornamental...

 What do you think constraints are used for otherwise ^^
Yes, I've seen it, thanks. Requiring the user to write the constraint might indeed enforce a better style, but I want to be able to test it even if the user forgets the constraint. Otherwise she'll get cryptic error messages from some other code assuming that CallsFoo!NoFoo is a valid type.
Jan 30
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 01/29/2016 09:01 AM, Adrian Matoga wrote:

 Oh, there's more:
 // this should fail:
 static assert(is(CallsFoo!NoFoo));
 // this should fail too:
 static assert(is(typeof({ alias Baz = CallsFoo!NoFoo; return Baz.init;
 }())));
 // and this:
 static assert(__traits(compiles, { alias Baz = CallsFoo!NoFoo; return
 Baz.init; }()));
 // but only this fails:
 alias Baz = CallsFoo!NoFoo;

 https://issues.dlang.org/show_bug.cgi?id=15623
As I noted on the bug report, they are work when moved from module scope to inside a function (e.g. main()). At least there's that workaround... Ali
Jan 29
parent Adrian Matoga <dlang.spam matoga.info> writes:
On Saturday, 30 January 2016 at 00:16:21 UTC, Ali Çehreli wrote:
 https://issues.dlang.org/show_bug.cgi?id=15623
As I noted on the bug report, they are work when moved from module scope to inside a function (e.g. main()). At least there's that workaround... Ali
Thanks a lot! Now I can continue my work. :)
Jan 30