www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - You know how I was saying in my DConf talk...

reply Ethan <gooberman gmail.com> writes:
...that I come up across metaprogramming problems that can't be 
easily Googled and making bug reports for is hard?

https://issues.dlang.org/show_bug.cgi?id=20072

I tried upgrading to 2.087.0 and got blindsided by an error that 
looks something like:

no property `somevar` for type `some.Type`, did you mean 
`some.Type.__anonymous.somevar`?

Writing some entirely unrelated code earlier using 2.086.1 got a 
similar error and finally twigged me to the fact that it is 
actually static foreach problem.

This highlights one of the other things I don't like when errors 
like this happens: D's quality of error messages is still not 
great. They've most definitely improved since DDMD happened, but 
they still seem predicated on the idea that people aren't going 
to be doing a lot of metaprogramming and provide almost no 
context when you're deep down the meta hole.

At least now that I know what the hey is going on, I can actually 
work at upgrading to 2.087.0 with a workaround, but that legit 
was going to block me from ever upgrading.

live code link: https://run.dlang.io/is/PBKQ80

example code direct:

import std.meta : AliasSeq;
import std.traits : moduleName;

string generateFor( string objectName )()
{
     return "struct " ~ objectName ~ "{ }";
}

alias StructNames = AliasSeq!( "StructOne", "StructTwo", 
"StructThree" );

static foreach( Name; StructNames )
{
     mixin( generateFor!Name );
}

pragma( msg, moduleName!StructOne );
Jul 23 2019
next sibling parent reply JN <666total wp.pl> writes:
On Tuesday, 23 July 2019 at 18:36:19 UTC, Ethan wrote:
 This highlights one of the other things I don't like when 
 errors like this happens: D's quality of error messages is 
 still not great. They've most definitely improved since DDMD 
 happened, but they still seem predicated on the idea that 
 people aren't going to be doing a lot of metaprogramming and 
 provide almost no context when you're deep down the meta hole.
That's how metaprogramming oriented languages are. Every language that has advanced metaprogramming like C++ or D sooner or later ends up in template spaghetti. Sure, the error messages are nice for simple templates, and performance is nice too, but once you have several generic types and then use them together, good luck, both on errors and compilation speed time. Oh and autocomplete breaks too because most of the code doesn't exist until build time.
Jul 23 2019
parent Ethan <gooberman gmail.com> writes:
On Tuesday, 23 July 2019 at 19:56:44 UTC, JN wrote:
 That's how metaprogramming oriented languages are. Every 
 language that has advanced metaprogramming like C++ or D sooner 
 or later ends up in template spaghetti.
Perhaps you're not familiar with MSVC's template error messages of late? Those things are tight. It's not an unsolvable problem. It's just not a problem that will serve a lot of people right now.
Jul 23 2019
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 23.07.19 20:36, Ethan wrote:
 ...that I come up across metaprogramming problems that can't be easily 
 Googled and making bug reports for is hard?
 
 https://issues.dlang.org/show_bug.cgi?id=20072
 
 I tried upgrading to 2.087.0 and got blindsided by an error that looks 
 something like:
 
 no property `somevar` for type `some.Type`, did you mean 
 `some.Type.__anonymous.somevar`?
 
 Writing some entirely unrelated code earlier using 2.086.1 got a similar 
 error and finally twigged me to the fact that it is actually static 
 foreach problem.
 
 This highlights one of the other things I don't like when errors like 
 this happens: D's quality of error messages is still not great. They've 
 most definitely improved since DDMD happened, but they still seem 
 predicated on the idea that people aren't going to be doing a lot of 
 metaprogramming and provide almost no context when you're deep down the 
 meta hole.
 
 At least now that I know what the hey is going on, I can actually work 
 at upgrading to 2.087.0 with a workaround, but that legit was going to 
 block me from ever upgrading.
 
 live code link: https://run.dlang.io/is/PBKQ80
 
 example code direct:
 
 import std.meta : AliasSeq;
 import std.traits : moduleName;
 
 string generateFor( string objectName )()
 {
      return "struct " ~ objectName ~ "{ }";
 }
 
 alias StructNames = AliasSeq!( "StructOne", "StructTwo", "StructThree" );
 
 static foreach( Name; StructNames )
 {
      mixin( generateFor!Name );
 }
 
 pragma( msg, moduleName!StructOne );
This shouldn't happen (the anonymous scope is an implementation detail and `__traits(parent, ...)` shouldn't return it, especially not for symbols that are not even `static foreach` loop variables). Is there already an issue for this? Also, this code compiles neither with 2.086.1 nor 2.087.0. Do you have an example that demonstrates a regression?
Jul 23 2019
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 24.07.19 02:51, Timon Gehr wrote:
 Is there already an issue for this?
Just noticed that the linked issue conflates both problems. I don't think that the visibility bug is the same as the `__traits(parent, ...)` one.
Jul 23 2019
prev sibling parent reply Ethan <gooberman gmail.com> writes:
On Wednesday, 24 July 2019 at 00:51:35 UTC, Timon Gehr wrote:
 This shouldn't happen (the anonymous scope is an implementation 
 detail and `__traits(parent, ...)` shouldn't return it, 
 especially not for symbols that are not even `static foreach` 
 loop variables). Is there already an issue for this? Also, this 
 code compiles neither with 2.086.1 nor 2.087.0. Do you have an 
 example that demonstrates a regression?
The entire point of that code I posted and the bug report I made is *to illustrate* that static foreach is broken. *OF COURSE* it shouldn't happen. And it shouldn't be this hard for an end user to work out what the problem is. 2.086.1 and 2.087.0 are the versions I've been developing on. Take the code, run it in prior DMDs. You'll find where it broke. I legit just pasted it in to godbolt and clicked on prior LDCs, it's been there as long as LDC has supported static foreach (ldc 1.6.0 based on dmd 2.076.1) Herringway on IRC even made a version without dependencies: static foreach( Name; [""] ) { struct StructOne {} } struct Z { static foreach( Name; [""] ) { struct StructOne {} } } pragma(msg, __traits(parent, StructOne).stringof); pragma(msg, __traits(parent, Z.StructOne).stringof);
Jul 23 2019
next sibling parent reply Ethan <gooberman gmail.com> writes:
On Wednesday, 24 July 2019 at 01:06:18 UTC, Ethan wrote:

It's 4am and I was planning on having a major feature finished 8 
hours ago, but I've been running in to static foreach and mixin 
bugs all day.
Jul 23 2019
parent reply Ethan <gooberman gmail.com> writes:
On Wednesday, 24 July 2019 at 01:10:34 UTC, Ethan wrote:
 On Wednesday, 24 July 2019 at 01:06:18 UTC, Ethan wrote:

 It's 4am and I was planning on having a major feature finished 
 8 hours ago, but I've been running in to static foreach and 
 mixin bugs all day.
https://issues.dlang.org/show_bug.cgi?id=20079 https://issues.dlang.org/show_bug.cgi?id=20080 ........and when trying to get to sleep, I decided to try forward declarations for the functions I was having issues with in mixins. And finally hit upon what I think are the root problems I've been having. Mixin templates have been broken in one way or another since I started using D in 2012. This static foreach bug I've found just seems to highlight to me that the method of defining a separate scope and importing in to the parent after the fact just plain doesn't work.
Jul 23 2019
next sibling parent reply Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 24 July 2019 at 02:12:53 UTC, Ethan wrote:
 On Wednesday, 24 July 2019 at 01:10:34 UTC, Ethan wrote:
 but I've been running in to static foreach and
 mixin bugs all day.
https://issues.dlang.org/show_bug.cgi?id=20079 https://issues.dlang.org/show_bug.cgi?id=20080
Those are by design and it is a fairly useful design too. The presence of a name in the outer scope overrides the same name from the mixin. This allows easy selective customizing of a mixin template as you use it.
Jul 23 2019
parent reply Ethan <gooberman gmail.com> writes:
On Wednesday, 24 July 2019 at 03:01:33 UTC, Adam D. Ruppe wrote:
 Those are by design and it is a fairly useful design too. The 
 presence of a name in the outer scope overrides the same name 
 from the mixin. This allows easy selective customizing of a 
 mixin template as you use it.
https://dlang.org/spec/template-mixin.html 3. Unlike a template instantiation, a template mixin's body is evaluated within the scope where the mixin appears, not where the template declaration is defined. It is analogous to cutting and pasting the body of the template into the location of the mixin into a nested scope. It is useful for injecting parameterized ‘boilerplate’ code, as well as for creating templated nested functions, which is not possible with template instantiations. So which one is it? Is it copy/paste and a replacement for parameterised C macros as sold, or is it something else? The spec here reeks of following the implementation instead of being clearly thought out. And it's far from the first time I've made this point.
Jul 23 2019
parent Adam D. Ruppe <destructionator gmail.com> writes:
On Wednesday, 24 July 2019 at 03:11:02 UTC, Ethan wrote:
 So which one is it? Is it copy/paste and a replacement for 
 parameterised C macros as sold, or is it something else?
That page never claims it is a replacement for C macros, and it said it is "analogous" to copy/paste, not identical to it, then goes on to describe specific behaviors. The details of names appear later on: https://dlang.org/spec/template-mixin.html#mixin_scope including the overriding behavior of locals, conflicts with multiple mixins, and more. So, yes, it is something else.
Jul 23 2019
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 24.07.19 04:12, Ethan wrote:
 On Wednesday, 24 July 2019 at 01:10:34 UTC, Ethan wrote:
 On Wednesday, 24 July 2019 at 01:06:18 UTC, Ethan wrote:

 It's 4am and I was planning on having a major feature finished 8 hours 
 ago, but I've been running in to static foreach and mixin bugs all day.
https://issues.dlang.org/show_bug.cgi?id=20079 https://issues.dlang.org/show_bug.cgi?id=20080 ...
This behavior is by design (for the better or worse, but those are not compiler bugs). You'd need to alias the mixin-template-local symbols into the current scope, or use string mixins instead of template mixins.
 ........and when trying to get to sleep, I decided to try forward 
 declarations for the functions I was having issues with in mixins. And 
 finally hit upon what I think are the root problems I've been having.
 
 Mixin templates have been broken in one way or another since I started 
 using D in 2012. This static foreach bug I've found just seems to 
 highlight to me that the method of defining a separate scope and 
 importing in to the parent after the fact just plain doesn't work.
mixin templates are _designed_ that way, but `static foreach` doesn't work like this. The additional scopes are introduced for the purpose of containing the `static foreach` loop variable symbols, the symbols generated by `static foreach` themselves are _not_ treated like template mixins, they are inserted into the symbol table of the enclosing scope, but they need to be analyzed in the inner scope so the `static foreach` loop variable is visible. The `static foreach` implementation explicitly skips scopes containing `static foreach` loop variables (the __anonymous in the error messages) when determining parent symbols, so there is something weird going on. I'm trying to look into this, but I don't have that much time and for some reason the compiler doesn't build on my machine right now (linker errors)... I have no idea what's up with the visibility problems, as I haven't worked on that part of DMD's code, but probably there is a bad interaction between the code that checks for symbol visibility and `static foreach` loop variable scopes.
Jul 23 2019
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 24.07.19 05:10, Timon Gehr wrote:
 
 The `static foreach` implementation explicitly skips scopes containing 
 `static foreach` loop variables (the __anonymous in the error messages) 
 when determining parent symbols, so there is something weird going on. 
 I'm trying to look into this, but I don't have that much time and for 
 some reason the compiler doesn't build on my machine right now (linker 
 errors)...
https://github.com/dlang/dmd/pull/10214
Jul 23 2019
parent reply Ethan <gooberman gmail.com> writes:
On Wednesday, 24 July 2019 at 03:56:44 UTC, Timon Gehr wrote:
 https://github.com/dlang/dmd/pull/10214
Thank you.
Jul 24 2019
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 24.07.19 16:21, Ethan wrote:
 On Wednesday, 24 July 2019 at 03:56:44 UTC, Timon Gehr wrote:
 https://github.com/dlang/dmd/pull/10214
Thank you.
No problem, sorry for screwing this up in the first place. Does the patch solve all of your `static foreach`-related problems?
Jul 24 2019
parent Ethan <gooberman gmail.com> writes:
On Thursday, 25 July 2019 at 00:15:22 UTC, Timon Gehr wrote:
 No problem, sorry for screwing this up in the first place. Does 
 the patch solve all of your `static foreach`-related problems?
I'll let you know when either I can compile DMD again, or the next point release comes out.
Jul 25 2019
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 24.07.19 03:06, Ethan wrote:
 On Wednesday, 24 July 2019 at 00:51:35 UTC, Timon Gehr wrote:
 This shouldn't happen (the anonymous scope is an implementation detail 
 and `__traits(parent, ...)` shouldn't return it, especially not for 
 symbols that are not even `static foreach` loop variables). Is there 
 already an issue for this? Also, this code compiles neither with 
 2.086.1 nor 2.087.0. Do you have an example that demonstrates a 
 regression?
The entire point of that code I posted and the bug report I made is *to illustrate* that static foreach is broken. *OF COURSE* it shouldn't happen. ...
As I am sure you are aware, this practice is called confirming a bug report. Not all of the issues you opened are in fact compiler bugs. Some of them are you misunderstanding the language specification. I asked whether you can demonstrates a regression because you said the problem arose when you updated compilers, but it seems it's because some deprecation period ended.
Jul 23 2019
prev sibling parent reply Kagamin <spam here.lot> writes:
On Tuesday, 23 July 2019 at 18:36:19 UTC, Ethan wrote:
 They've most definitely improved since DDMD happened, but they 
 still seem predicated on the idea that people aren't going to 
 be doing a lot of metaprogramming and provide almost no context 
 when you're deep down the meta hole.
The compiler on run.dlang.org provides plenty of context: /dlang/dmd/linux/bin64/../../src/phobos/std/traits.d(482): Error: local scope __anonymous is not a variable /dlang/dmd/linux/bin64/../../src/phobos/std/traits.d(580): Error: template instance `std.traits.parentOf!(StructOne)` error instantiating onlineapp.d(16): instantiated from here: moduleName!(StructOne) onlineapp.d(16): while evaluating pragma(msg, moduleName!(StructOne)) It provides instantiation stack and all line numbers where error occurs.
Jul 26 2019
parent reply Ethan <gooberman gmail.com> writes:
On Friday, 26 July 2019 at 10:33:29 UTC, Kagamin wrote:
 The compiler on run.dlang.org provides plenty of context:

 /dlang/dmd/linux/bin64/../../src/phobos/std/traits.d(482): 
 Error: local scope __anonymous is not a variable
 /dlang/dmd/linux/bin64/../../src/phobos/std/traits.d(580): 
 Error: template instance `std.traits.parentOf!(StructOne)` 
 error instantiating
 onlineapp.d(16):        instantiated from here: 
 moduleName!(StructOne)
 onlineapp.d(16):        while evaluating pragma(msg, 
 moduleName!(StructOne))

 It provides instantiation stack and all line numbers where 
 error occurs.
Simple use cases like my example are not the problem. There's an error I was getting the other day that doesn't give a line number, just a file. Another one starts with "COMPILE". Both of those required unrolling code and tinkering to work out what was wedged in their bonnet. And of course I have no idea how to reproduce them either because they're deep in mixins in templated functions in templates in mixins. I do not write normal code in D. But down in my meta rabbit hole is where all of D's real ultimate power is.
Jul 26 2019
parent reply FeepingCreature <feepingcreature gmail.com> writes:
On Friday, 26 July 2019 at 12:56:07 UTC, Ethan wrote:
 There's an error I was getting the other day that doesn't give
 a line number, just a file.
 
 Another one starts with "COMPILE".
 
 Both of those required unrolling code and tinkering to work out 
 what was wedged in their bonnet.

 And of course I have no idea how to reproduce them either 
 because they're deep in mixins in templated functions in 
 templates in mixins.

 I do not write normal code in D. But down in my meta rabbit 
 hole is where all of D's real ultimate power is.
I would like to voice a very enthusiastic recommendation for Dustmite for reducing programs to tests. Since it just requires a pass/fail test, it's easy to write a shellscript that checks that DMD's output matches a specific pattern, such as "COMPILE:.*".
Jul 26 2019
parent reply Ethan <gooberman gmail.com> writes:
On Friday, 26 July 2019 at 13:02:21 UTC, FeepingCreature wrote:
 I would like to voice a very enthusiastic recommendation for 
 Dustmite for reducing programs to tests. Since it just requires 
 a pass/fail test, it's easy to write a shellscript that checks 
 that DMD's output matches a specific pattern, such as 
 "COMPILE:.*".
Honestly, hot take/opinion time here. But every time I hear someone say "Dustmite" my immediate reaction is "Well I guess D isn't ready for production code." Let's have a for real example. I have a static assert in my receive function. If it detects that you've defined a message but haven't provided an implementation for receiving that message, it'll helpfully tell you exactly what you need to do. to generate correct message responses for an entire class of messages dealing with creating/syncing/deleting objects. Inside these functions, of course I write errors. Outside of {} braces, I almost never write any given line of code once. Things I haven't imported, typos, whatever. Nothing ever compiles first time. So I hit compile expecting to see what kind of problems are going on now. My static assert fires saying that this message isn't defined, compile stops dead in its tracks. I sit there going "what the Zod" for twenty minutes, double checking template definitions, rewriting template declarations, before I finally decide to go in to my send function and comment out the static assert and just let the compiler error on the receive call. Errors start showing up as normal in my templated functions. So what's going on here? Internally, the compiler knows my templated function won't compile. It knows there's an error. It knows the symbol can't be defined. But instead of giving me the errors for what's going on there first, it sees my static assert and jumps off a rather tall cliff taking everything it knows with it. Now, I could Dustmite my project. Which currently sits at 73 .d the moment, but I autogenerate a bunch of it and depenency properties are responsible for a ton of pointless bloat - but that's a digression.) Throw in Binderoo as well since I can't use off somewhere I won't touch and let it run for potentially days finding a minimal reproducible set. Or maybe I could spend the time to isolate and work out what makes the compiler do these weird things. Or I could do what I do daily in a production environment - fix or workaround the bug and get on trying to meet a deadline. I'll take door number three thanks. That potential customer isn't going to care how many bug reports I write, especially since I inevitably come across something a couple of hours later that should be Dustmited... Dustmote... Dusted. Whatever. I don't have that much CPU power to spare. Now. I know that's also a counter-productive viewpoint to have. "I got a bug!" Great, submit a bug report with a reproducible case. "I don't have the time!" Who else but me, right? But the overall point I started making at the start of this post is that door number three point. Get D in to a production environment, people aren't going to engage in jolly community co-operation. They want to get their job done, meet their goals/targets, get paid, eat, and generally just complain to their co-workers about the latest weird <yeah, imagine I broke the white-collar forum protocol here> that D is doing. Like every other colleague you've ever known using every other language you've ever used professionally. Wrapping up. Short of ye olde corporate "sign this NDA and get the keys to my codebase" approach to look at, I'm not sure what the middle ground is.
Jul 26 2019
next sibling parent FeepingCreature <feepingcreature gmail.com> writes:
On Friday, 26 July 2019 at 15:02:43 UTC, Ethan wrote:
 Now, I could Dustmite my project. Which currently sits at 73 .d 

 at the moment, but I autogenerate a bunch of it and depenency 
 properties are responsible for a ton of pointless bloat - but 
 that's a digression.) Throw in Binderoo as well since I can't 

 all off somewhere I won't touch and let it run for potentially 
 days finding a minimal reproducible set.

 Or maybe I could spend the time to isolate and work out what 
 makes the compiler do these weird things.

 Or I could do what I do daily in a production environment - fix 
 or workaround the bug and get on trying to meet a deadline.
Fair enough. When I hit a situation like that, I do take the time to dustmite things down and file a bug (and PR, if possible), but I am very much blessed to have a boss who understands that if you hit a bug, you can't really expect things to improve if you don't file a report, and that my coworkers have patience for me to wander off on a bug filing/fixing tangent. On the other hand, a lot of our longstanding pain points with D have actually gotten fixed, and none of that would have happened if there hadn't been bug reports. If you're long-term committed to a language, chances are that bug will show up again and waste hours of your time again. At some point it becomes cheaper to just file and fix it, instead of spending weeks of a new coworker's onboarding time getting them up to speed on all the D issues you've learnt to sidestep. And no, this does not exactly say good things about D for production use...
Jul 26 2019
prev sibling parent reply Kagamin <spam here.lot> writes:
On Friday, 26 July 2019 at 15:02:43 UTC, Ethan wrote:
 I have a static assert in my receive function. If it detects 
 that you've defined a message but haven't provided an 
 implementation for receiving that message, it'll helpfully tell 
 you exactly what you need to do.

 comment out the static assert and just let the compiler error 
 on the receive call.
Isn't your complaint that the assert is not helpful? If it was helpful and told exactly what you need to do, why do you need to remove it and debug?
Jul 27 2019
parent reply Ethan <gooberman gmail.com> writes:
On Saturday, 27 July 2019 at 09:14:54 UTC, Kagamin wrote:
 Isn't your complaint that the assert is not helpful?
No, the complaint is that DMD withheld error information in favor of my static assert.
 If it was helpful and told exactly what you need to do, why do 
 you need to remove it and debug?
Because DMD withheld error information in favor of my static assert. So. Since I clearly didn't contextualise this properly. The static assert itself is in a mixin template. It is used in four objects currently - two different kinds of clients, and the server receivers that limit what they can do. This is why the static assert was added in the first place - an error would happen, DMD would report the error location as being inside a mixin without context as to where the mixin was invoked, and I'd be left wondering which part of my code I overlooked this time. Messages themselves are implemented in a mixin template. Mix them all in to the same class. Normally, these messages will compile, throw the error, and then the static assert will tell you the handy information. In this case, I wasn't getting the error messages and no idea of why the static assert was firing. This just plain appears to be a static assert problem in general. Probably by design, except the spec doesn't mention that static assert is dependent on scope resolution order. Here's an example without templates that illustrates what I'm referring to. Move the static assert inside main() and you get the behavior I was expecting. https://run.dlang.io/is/rjTRks -- void broken() { doesntexist(); } int main( string[] args ) { broken(); } static assert( false, "so here's a static assert" );
Jul 27 2019
parent reply Kagamin <spam here.lot> writes:
On Saturday, 27 July 2019 at 11:24:11 UTC, Ethan wrote:
 https://run.dlang.io/is/rjTRks

 --

 void broken()
 {
     doesntexist();
 }

 int main( string[] args )
 {
     broken();
 }

 static assert( false, "so here's a static assert" );
Again, in this example the compiler does provide context that assert fails at line 11. Function bodies are compiled at a later stage and it doesn't make sense to compile them if top level declarations failed to compile, if `doesntexist` only failed to compile and its every usage is reported as an error, it will be a very big amount of errors, which isn't helpful.
Jul 27 2019
parent reply Ethan <gooberman gmail.com> writes:
On Saturday, 27 July 2019 at 16:36:35 UTC, Kagamin wrote:
 Again, in this example the compiler does provide context that 
 assert fails at line 11. Function bodies are compiled at a 
 later stage and it doesn't make sense to compile them if top 
 level declarations failed to compile
Your definition of context is incomplete. I cannot think of a single programmer that wants to hit compile every time they fix one single compiler error just to find another single compile error. Stopping at one static assert is undesired behavior in a production environment. If this behavior is by design, it's terrible design.
Jul 27 2019
next sibling parent reply Kagamin <spam here.lot> writes:
When a function is compiled in incorrect environment it's likely 
to report induced errors, and those are very confusing. Do 
programmers want to hunt for induced errors? When the compiler is 
invoked in console and first prints the relevant error and then 
lots of induced errors, they will scroll the relevant error out 
of sight, the fact that stacks are printed inside out is a little 
unwieldy too.
Jul 27 2019
parent Ethan <gooberman gmail.com> writes:
On Saturday, 27 July 2019 at 18:59:20 UTC, Kagamin wrote:
 Something
Is that proving my point? I think it is. It appears you implied a programmer will hunt for the correct error message given a complete output. Which the current static assert functionality is not making possible. Either that or you're arguing that reducing the context of an error message is helpful to someone. Which, hey, I've got news for you.
Jul 27 2019
prev sibling next sibling parent reply Bastiaan Veelo <Bastiaan Veelo.net> writes:
On Saturday, 27 July 2019 at 16:59:36 UTC, Ethan wrote:
 Stopping at one static assert is undesired behavior in a 
 production environment.
If continuing is desired, would a `static if` combined with `pragma (msg, ...)` not be more appropriate than `static assert`? This can probably go into a ct function like `static_check`. Bastiaan.
Jul 27 2019
parent reply Ethan <gooberman gmail.com> writes:
On Saturday, 27 July 2019 at 22:19:20 UTC, Bastiaan Veelo wrote:
 If continuing is desired, would a `static if` combined with 
 `pragma (msg, ...)` not be more appropriate than `static 
 assert`? This can probably go into a ct function like 
 `static_check`.

 Bastiaan.
I was considering making that point myself. The static assert here is kinda useless, a pragma( msg ) won't stop compilation. This is in that weird <non-PC word> area that people keep bringing up. The recommended course of development with templates is to static assert with your own handy error message. The reality is that you lose vital information about why that template is not instantiating unless you litter your code with static ifs and pragma( msg )s.
Jul 27 2019
parent Bastiaan Veelo <Bastiaan Veelo.net> writes:
On Saturday, 27 July 2019 at 22:22:57 UTC, Ethan wrote:
 On Saturday, 27 July 2019 at 22:19:20 UTC, Bastiaan Veelo wrote:
 If continuing is desired, would a `static if` combined with 
 `pragma (msg, ...)` not be more appropriate than `static 
 assert`? This can probably go into a ct function like 
 `static_check`.

 Bastiaan.
I was considering making that point myself. The static assert here is kinda useless, a pragma( msg ) won't stop compilation. This is in that weird <non-PC word> area that people keep bringing up. The recommended course of development with templates is to static assert with your own handy error message. The reality is that you lose vital information about why that template is not instantiating unless you litter your code with static ifs and pragma( msg )s.
Tossing in a `version` may produce a helpful idiom, if compilation should continue during lib dev and stop during lib usage: ``` import std; void my_static_assert(alias condition, string message)() { version(continue_past_assert) { static if (!condition) pragma(msg, message); } else { static assert(condition, message); } } void main() { my_static_assert!(false, "fix your mistake"); writeln("Hello D"); } ``` https://run.dlang.io/is/5NqYj7
Jul 27 2019
prev sibling parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Saturday, 27 July 2019 at 16:59:36 UTC, Ethan wrote:
 On Saturday, 27 July 2019 at 16:36:35 UTC, Kagamin wrote:
 Again, in this example the compiler does provide context that 
 assert fails at line 11. Function bodies are compiled at a 
 later stage and it doesn't make sense to compile them if top 
 level declarations failed to compile
Your definition of context is incomplete. I cannot think of a single programmer that wants to hit compile every time they fix one single compiler error just to find another single compile error. Stopping at one static assert is undesired behavior in a production environment. If this behavior is by design, it's terrible design.
How would you propose changing the compiler such that you got the "right" amount of errors, without any spurious ones? IIRC the current design "poisons" anything derived from an error to minimise error spam. In D it's very easy for one little typo to invalidate vast amounts of code, which leads to massive cascading errors.
Jul 28 2019
parent reply Ethan <gooberman gmail.com> writes:
On Sunday, 28 July 2019 at 11:41:20 UTC, John Colvin wrote:
 In D it's very easy for one little typo to invalidate vast 
 amounts of code, which leads to massive cascading errors.
I mean, that's true of C++ as well.
 How would you propose changing the compiler such that you got 
 the "right" amount of errors, without any spurious ones? IIRC 
 the current design "poisons" anything derived from an error to 
 minimise error spam.
I've long held the view that DMD's error reporting is not that great. And after my recent poke at the C++ mangler code and seeing the state of things... The move to DDMD means it's time to revist the reasons for why error reporting was done like that in the first place. First and foremost, my constant battle for *any* error generated while processing code must show the file and line it was processing at the time. I know Walter's view is "you know what code you were just writing." But the reality of software development in D (templates and mixins and metaprogramming, oh my!) and software development in general (pull a source code database from the internet and compile it with a newer version of a compiler than it was generated on) means that the point becomes increasingly irrelevant as time and complexity increases from when a piece of code was originally written. My other battle is error codes. Microsoft's documentation is spot on there. Your compiler generates an error code. Copy that code and stick it in to Google. Microsoft results up top, StackOverflow/etc right beneath it. Now you can go directly to relevant articles instead of trying to strip all context out of the message like type names and Google things that way, which is really inconsistent in the results you can get. The old argument that error codes increase the execution time of a compile, or the compilation time of DMD, surely must be irrelevant now. All this stuff can be handled with D's metaprogramming capabilities for no runtime cost. Don't make a table that needs static initialisation, make a table and assign it to an enum. The error function already works as a printf, so that's not a problem. You can even reduce the number of error calls you need to make, since the error code can contain information on whether it's a fatal error that stops the compiler or not. Currently that's two calls - one to error() and one to fatal(). And with all those error codes centralised, you can also generate documentation and upload it to dlang.org. Imagine the luxury of searching documentation instead of disparate forum posts for information on your error. So with all this in place. static_assert is currently treated as a fatal(), right? But I don't want it to. But some people desire that behavior. So surely we can parameterise static_assert in some manner to allow this?
Jul 29 2019
parent reply Kagamin <spam here.lot> writes:
On Monday, 29 July 2019 at 15:28:02 UTC, Ethan wrote:
 On Sunday, 28 July 2019 at 11:41:20 UTC, John Colvin wrote:
 In D it's very easy for one little typo to invalidate vast 
 amounts of code, which leads to massive cascading errors.
I mean, that's true of C++ as well.
From C++20 overview https://hackaday.com/2019/07/30/c20-is-feature-complete-heres-what changes-are-coming/ :
As a result, the compiler can provide a short and meaningful 
error message if the defined requirement of a concept isn’t met, 
instead of dumping walls of errors and warnings from somewhere 
deep within the template code itself that won’t make much sense 
without digging further into that code.
Looks like C++ compilers are supposed to print less errors too.
Jul 31 2019
parent Ethan <gooberman gmail.com> writes:
On Wednesday, 31 July 2019 at 13:21:01 UTC, Kagamin wrote:
As a result, the compiler can provide a short and meaningful 
error message if the defined requirement of a concept isn’t 
met, instead of dumping walls of errors and warnings from 
somewhere deep within the template code itself that won’t make 
much sense without digging further into that code.
Looks like C++ compilers are supposed to print less errors too.
Let's take a closer look, shall we....
As a result, the compiler can provide a short and meaningful 
error message if the defined requirement of a concept isn’t met
the compiler can provide a short and meaningful error message
short and meaningful error message
meaningful error message
Perhaps you missed the point where I'm complaining that the static assert behavior *HIDES* short meaningful error messages. Come back to reality. We miss you.
Jul 31 2019