www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Help from the compiler when debugging failing template constraints - a

reply Atila Neves <atila.neves gmail.com> writes:
I've mentioned this many times before: template constraints are 
like unittest blocks with asserts in D: great that they're 
built-in easy to use. But when they fail, there's no help in 
figuring out why.

I've had many a debugging session (with pragma(msg) of course, 
since my bugs were of the compile-time variety and there's no 
debugger for that) due to failing to satisfy a template 
constraint that I thought I'd implemented the correct functions 
for. It'd be nice if the compiler told me why. I did a PR a while 
back with an idea from Adam's book but it didn't work in the 
context of Phobos and interfaces. I've come up with a PR 
(https://github.com/D-Programming-Language/phobos/pull/3677) that 
will let users type this:

      models!(MyStruct, isInputRange)
     struct MyStruct { ... }

Or this:

     struct MyStruct {
         ...
         static assert(models!(MyStruct, isInputRange));
     }

When the template constraint isn't satisfied, the compiler will 
dutifully tell you why. The only requirement is that there be a 
checkXXX function for an isXXX template constraint. I've updated 
the original PR for `isInputRange` to make the above code 
possible. I chose the name `models` because I just got back from 
CppCon and concepts might have tainted my brain. It's unfortunate 
to have to specify the type in the UDA version, but it's what the 
language as it is now will allow me to do.

I created an input range, verified it compiled, then added a 't' 
to the end of `front`. With `models` I got this for both UDA and 
static assert versions:

/home/atila/coding/d/dlang/phobos/std/range/primitives.d(182): 
Error: template std.range.primitives.front cannot deduce function 
from argument types !()(Foo), candidates are:
/home/atila/coding/d/dlang/phobos/std/range/primitives.d(2219):   
      std.range.primitives.front(T)(T[] a) if 
(!isNarrowString!(T[]) && !is(T[] == void[]))
/home/atila/coding/d/dlang/phobos/std/range/primitives.d(2247):   
      std.range.primitives.front(T)(T[] a) if 
(isNarrowString!(T[]))
/home/atila/coding/d/dlang/phobos/std/traits.d-mixin-6771(6771): 
Error: template instance 
std.range.primitives.checkInputRange!(Foo) error instantiating
concepts.d(81):        instantiated from here: models!(Foo, 
isInputRange)
Failed: ["dmd", "-unittest", "-main", "-v", "-o-", "concepts.d", 
"-I."]


With `static assert(isInputRange!Foo)`, I get this:

concepts.d(87): Error: static assert  (isInputRange!(Foo)) is 
false
Failed: ["dmd", "-unittest", "-main", "-v", "-o-", "concepts.d", 
"-I."]

I prefer the first one. How about you?

Atila
Sep 28 2015
next sibling parent Jack Stouffer <jack jackstouffer.com> writes:
On Monday, 28 September 2015 at 20:25:21 UTC, Atila Neves wrote:
 I prefer the first one. How about you?

 Atila
Absolutely. The tedious hunt down with pragma(msg) needs to go. One thing your example doesn't show is the next step after the static assert fails: copy all of the asserts from the isWhatEver code an write a pragma(msg) for each of those to find where the problem is. I believe that the error messages should be of the same quality as the error messages when a class doesn't conform to an interface, but this is a good start.
Sep 28 2015
prev sibling next sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 9/28/15 4:25 PM, Atila Neves wrote:
 I've mentioned this many times before: template constraints are like
 unittest blocks with asserts in D: great that they're built-in easy to
 use. But when they fail, there's no help in figuring out why.

 I've had many a debugging session (with pragma(msg) of course, since my
 bugs were of the compile-time variety and there's no debugger for that)
 due to failing to satisfy a template constraint that I thought I'd
 implemented the correct functions for. It'd be nice if the compiler told
 me why. I did a PR a while back with an idea from Adam's book but it
 didn't work in the context of Phobos and interfaces. I've come up with a
 PR (https://github.com/D-Programming-Language/phobos/pull/3677) that
 will let users type this:

       models!(MyStruct, isInputRange)
      struct MyStruct { ... }

 Or this:

      struct MyStruct {
          ...
          static assert(models!(MyStruct, isInputRange));
      }

 When the template constraint isn't satisfied, the compiler will
 dutifully tell you why. The only requirement is that there be a checkXXX
 function for an isXXX template constraint. I've updated the original PR
 for `isInputRange` to make the above code possible. I chose the name
 `models` because I just got back from CppCon and concepts might have
 tainted my brain. It's unfortunate to have to specify the type in the
 UDA version, but it's what the language as it is now will allow me to do.

 I created an input range, verified it compiled, then added a 't' to the
 end of `front`. With `models` I got this for both UDA and static assert
 versions:

 /home/atila/coding/d/dlang/phobos/std/range/primitives.d(182): Error:
 template std.range.primitives.front cannot deduce function from argument
 types !()(Foo), candidates are:
 /home/atila/coding/d/dlang/phobos/std/range/primitives.d(2219):
 std.range.primitives.front(T)(T[] a) if (!isNarrowString!(T[]) &&
 !is(T[] == void[]))
 /home/atila/coding/d/dlang/phobos/std/range/primitives.d(2247):
 std.range.primitives.front(T)(T[] a) if (isNarrowString!(T[]))
 /home/atila/coding/d/dlang/phobos/std/traits.d-mixin-6771(6771): Error:
 template instance std.range.primitives.checkInputRange!(Foo) error
 instantiating
 concepts.d(81):        instantiated from here: models!(Foo, isInputRange)
 Failed: ["dmd", "-unittest", "-main", "-v", "-o-", "concepts.d", "-I."]


 With `static assert(isInputRange!Foo)`, I get this:

 concepts.d(87): Error: static assert  (isInputRange!(Foo)) is false
 Failed: ["dmd", "-unittest", "-main", "-v", "-o-", "concepts.d", "-I."]

 I prefer the first one. How about you?
Yes. I also prefer that the compiler do this. I've definitely run into this before: http://forum.dlang.org/post/m4mdsk$bgs$1 digitalmars.com -Steve
Sep 29 2015
prev sibling next sibling parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
On 28-Sep-2015 23:25, Atila Neves wrote:
 I've mentioned this many times before: template constraints are like
 unittest blocks with asserts in D: great that they're built-in easy to
 use. But when they fail, there's no help in figuring out why.
[snip]
 I created an input range, verified it compiled, then added a 't' to the
 end of `front`. With `models` I got this for both UDA and static assert
 versions:

 /home/atila/coding/d/dlang/phobos/std/range/primitives.d(182): Error:
 template std.range.primitives.front cannot deduce function from argument
 types !()(Foo), candidates are:
 /home/atila/coding/d/dlang/phobos/std/range/primitives.d(2219):
 std.range.primitives.front(T)(T[] a) if (!isNarrowString!(T[]) &&
 !is(T[] == void[]))
 /home/atila/coding/d/dlang/phobos/std/range/primitives.d(2247):
 std.range.primitives.front(T)(T[] a) if (isNarrowString!(T[]))
 /home/atila/coding/d/dlang/phobos/std/traits.d-mixin-6771(6771): Error:
 template instance std.range.primitives.checkInputRange!(Foo) error
 instantiating
 concepts.d(81):        instantiated from here: models!(Foo, isInputRange)
 Failed: ["dmd", "-unittest", "-main", "-v", "-o-", "concepts.d", "-I."]


 With `static assert(isInputRange!Foo)`, I get this:

 concepts.d(87): Error: static assert  (isInputRange!(Foo)) is false
 Failed: ["dmd", "-unittest", "-main", "-v", "-o-", "concepts.d", "-I."]

 I prefer the first one. How about you?

 Atila
Certainly the first one. -- Dmitry Olshansky
Sep 29 2015
prev sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Monday, 28 September 2015 at 20:25:21 UTC, Atila Neves wrote:
 I've mentioned this many times before: template constraints are 
 like unittest blocks with asserts in D: great that they're 
 built-in easy to use. But when they fail, there's no help in 
 figuring out why.

 [...]
Huh, I thought this'd get more interest. I guess I have weird priorities! :P Atila
Oct 14 2015
parent reply Artur Skawina via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 10/14/15 10:26, Atila Neves via Digitalmars-d wrote:
 On Monday, 28 September 2015 at 20:25:21 UTC, Atila Neves wrote:
 I've mentioned this many times before: template constraints are like unittest
blocks with asserts in D: great that they're built-in easy to use. But when
they fail, there's no help in figuring out why.

 [...]
Huh, I thought this'd get more interest. I guess I have weird priorities! :P
No, it's probably just that the people interested in this would prefer a /proper/ solution, hence don't consider ad hoc hacks to be cost effective, but actually counterproductive. artur
Oct 14 2015
parent reply Atila Neves <atila.neves gmail.com> writes:
On Wednesday, 14 October 2015 at 12:42:23 UTC, Artur Skawina 
wrote:
 On 10/14/15 10:26, Atila Neves via Digitalmars-d wrote:
 On Monday, 28 September 2015 at 20:25:21 UTC, Atila Neves 
 wrote:
 I've mentioned this many times before: template constraints 
 are like unittest blocks with asserts in D: great that 
 they're built-in easy to use. But when they fail, there's no 
 help in figuring out why.

 [...]
Huh, I thought this'd get more interest. I guess I have weird priorities! :P
No, it's probably just that the people interested in this would prefer a /proper/ solution, hence don't consider ad hoc hacks to be cost effective, but actually counterproductive. artur
There can't be a "proper" solution without a language change, which is unlikely. Personally, I'd prefer struct MyStruct: static isInputRange { ... } to: models!(MyStruct, isInputRange) struct MyStruct { ... } But the latter is possible today and the former is unlikely to ever get approved. My original plan was to write a DIP for "static inheritance", I changed to this PR because I'm 90% sure the DIP would go nowhere and the PR makes things a lot better. Atila
Oct 14 2015
next sibling parent Artur Skawina via Digitalmars-d <digitalmars-d puremagic.com> writes:
On 10/14/15 15:32, Atila Neves via Digitalmars-d wrote:
 On Wednesday, 14 October 2015 at 12:42:23 UTC, Artur Skawina wrote:
 On 10/14/15 10:26, Atila Neves via Digitalmars-d wrote:
 On Monday, 28 September 2015 at 20:25:21 UTC, Atila Neves wrote:
 I've mentioned this many times before: template constraints are like unittest
blocks with asserts in D: great that they're built-in easy to use. But when
they fail, there's no help in figuring out why.

 [...]
Huh, I thought this'd get more interest. I guess I have weird priorities! :P
No, it's probably just that the people interested in this would prefer a /proper/ solution, hence don't consider ad hoc hacks to be cost effective, but actually counterproductive.
There can't be a "proper" solution without a language change, which is unlikely.
Yes, I'm just pointing out that the lack of discussion is not necessarily caused by the lack of interest and that the subject is not a low priority one. When a /proper/ solution is available (ie `possible`, even if not `likely`), discussing partial solutions (aka hacks) that have a significant cost will (rightly) be seen as counterproductive. Given the microscopic size of the D community it only takes a few people to reach that conclusion to result in ~zero constructive feedback. IOW it's not a "weird priorities" issue; it's a pragmatic pro-status-quo-choice issue. Another example of this kind would be the ownership/lifetime approach. Of the three options: [A] `ignoring it by-design` (C-like), [B] `dealing with only a subset`, and [C] `handling it properly`, the middle [B] option is the worst one. This leads to very little serious feedback to [B] proposals, and even less to [C] (since it "won't happen"). That doesn't change the reality that the only viable alternatives are either [A] or [C], because [B] has a cost comparable (if not ultimately even higher than) [C], but does not have [C]'s benefit (safety). IOW "feedback amount" can not be used as a proxy for "interest", and there often is no meaningful feedback->result correlation. There are too many other (meta) factors involved. artur
Oct 14 2015
prev sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Wednesday, 14 October 2015 at 13:32:54 UTC, Atila Neves wrote:
 ever get approved. My original plan was to write a DIP for 
 "static inheritance",
I would be intersted in seeing a detailed analysis on the difference between inheritance and "alias this" over the first struct member.
Oct 14 2015
parent reply deadalnix <deadalnix gmail.com> writes:
On Wednesday, 14 October 2015 at 20:12:52 UTC, Ola Fosheim 
Grøstad wrote:
 On Wednesday, 14 October 2015 at 13:32:54 UTC, Atila Neves 
 wrote:
 ever get approved. My original plan was to write a DIP for 
 "static inheritance",
I would be intersted in seeing a detailed analysis on the difference between inheritance and "alias this" over the first struct member.
No virtual dispatch, no downcast possible, no dynamic typeid, ...
Oct 14 2015
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= writes:
On Thursday, 15 October 2015 at 01:08:18 UTC, deadalnix wrote:
 On Wednesday, 14 October 2015 at 20:12:52 UTC, Ola Fosheim 
 Grøstad wrote:
 On Wednesday, 14 October 2015 at 13:32:54 UTC, Atila Neves 
 wrote:
 ever get approved. My original plan was to write a DIP for 
 "static inheritance",
I would be intersted in seeing a detailed analysis on the difference between inheritance and "alias this" over the first struct member.
No virtual dispatch, no downcast possible, no dynamic typeid, ...
Does this mean that static inheritance for structs can be done as syntax sugar using "alias this" with no semantic changes and get the same semantics as with a class? E.g.: struct MySub : MySuper { } translates into struct MySub { MySuper __super; this(...){ __super.__ctor; ...} ~this(...){ ...; __super.__dtor;} alias __super this; }
Oct 14 2015
parent Atila Neves <atila.neves gmail.com> writes:
On Thursday, 15 October 2015 at 06:46:25 UTC, Ola Fosheim Grøstad 
wrote:
 On Thursday, 15 October 2015 at 01:08:18 UTC, deadalnix wrote:
 On Wednesday, 14 October 2015 at 20:12:52 UTC, Ola Fosheim 
 Grøstad wrote:
 [...]
No virtual dispatch, no downcast possible, no dynamic typeid, ...
Does this mean that static inheritance for structs can be done as syntax sugar using "alias this" with no semantic changes and get the same semantics as with a class? E.g.: struct MySub : MySuper { } translates into struct MySub { MySuper __super; this(...){ __super.__ctor; ...} ~this(...){ ...; __super.__dtor;} alias __super this; }
All I want from static inheritance is exactly what's made possible by the `models` PR. I guess I'll write that DIP after all. Atila
Oct 15 2015