www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - My late christmas present for you: context-aware assertion error

reply Seb <seb wilzba.ch> writes:
tl;dr: I was annoyed for years that D's assert are so non 
informative AssertError, so here's my late Christmas present for 
the D community. With 2.085 DMD will gain an experimental flag 
for more informative assertion errors. Feedback on this 
experimental feature is welcome, s.t. we eventually can enable it 
by default.

Example:

---
void main()
{
     int a = 1, b = 2;
     assert(a == b); // ERROR: 1 != 2
}
---

```
 dmd -run onlineapp.d
core.exception.AssertError onlineapp.d(4): 1 != 2 ---------------- ??:? _d_assert_msg [0xb150e350] ??:? _Dmain [0xb150d627] ``` Play online: https://run.dlang.io/is/GMfe9S Full changelog: https://dlang.org/changelog/pending.html#assert Where to start hacking: - https://github.com/dlang/dmd/blob/00299e3b6ca9dcd5a5dc8bd50280b63d0bdc51f9/src/dmd/expressionsem.d#L5559 - https://github.com/dlang/druntime/blob/master/src/core/internal/dassert.d - https://github.com/dlang/dmd/pull/8517 Q: Why not just introduce an `assertEqual` user function? A: - there's a lot of already written D code out there that uses `assert` [1] - `assertEqual` wouldn't cut, it because then we would need to have an `assertLessThan` etc. too Q: Why put this in the compiler and not in fluent-assert or similar library? A: - there's a lot of already written D code out there that uses `assert` [1] - not everyone wants to use a library just to have somewhat decent assert messages - libraries can only do sth. like `testedValue.should.equal(42)`, but the compiler can deal with `testedValue == 42` [1] https://github.com/search?l=D&q=assert&type=Code Error context ------------- Also note that with 2.085 DMD will get -verrors=context --- void foo() { a = 1; } --- ```
 dmd -verrors=context onlineapp.d
onlineapp.d(3): Error: undefined identifier a a = 1; ^ ``` Full changelog: https://dlang.org/changelog/pending.html#error-context Play online: https://run.dlang.io/is/8gsye1 Thanks to all the people (Jacob Carlborg, Petar Kirov, Nicolas Wilson, Rainer Schuetze, etc.) who helped me to get this feature into DMD! Merry Christmas!
Jan 12
next sibling parent Andre Pany <andre s-e-a-p.de> writes:
On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
...
 Full changelog: 
 https://dlang.org/changelog/pending.html#error-context
 Play online: https://run.dlang.io/is/8gsye1

 Thanks to all the people (Jacob Carlborg, Petar Kirov, Nicolas 
 Wilson, Rainer Schuetze, etc.) who helped me to get this 
 feature into DMD!

 Merry Christmas!
Thanks for this great features. 2019 will be again a very great year for D! Kind regards Andre
Jan 12
prev sibling next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sat, Jan 12, 2019 at 03:34:02PM +0000, Seb via Digitalmars-d wrote:
[...]
 ---
 void main()
 {
     int a = 1, b = 2;
     assert(a == b); // ERROR: 1 != 2
 }
 ---
 
 ```
 dmd -run onlineapp.d
core.exception.AssertError onlineapp.d(4): 1 != 2
Awesome! [...]
 Also note that with 2.085 DMD will get -verrors=context
[...]
 ---
 void foo()
 {
     a = 1;
 }
 ---
 
 
 ```
 dmd -verrors=context onlineapp.d
onlineapp.d(3): Error: undefined identifier a a = 1; ^ ```
Awesome! It's about time dmd error messages got a facelift. Will -verrors=context eventually become the default? T -- The irony is that Bill Gates claims to be making a stable operating system and Linus Torvalds claims to be trying to take over the world. -- Anonymous
Jan 12
parent reply Seb <seb wilzba.ch> writes:
On Saturday, 12 January 2019 at 16:17:07 UTC, H. S. Teoh wrote:
 Awesome!

 It's about time dmd error messages got a facelift.  Will 
 -verrors=context eventually become the default?
Yes, I hope so! Once it has gotten a fair bit of real-world feedback and testing (which is the one of the reasons why I opened this thread) we can enable it by default if a TTY is detected. TTY detection is probably necessary as there are still a lot of programs (especially editor plugins) which parse the DMD output.
Jan 12
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sat, Jan 12, 2019 at 04:23:53PM +0000, Seb via Digitalmars-d wrote:
 On Saturday, 12 January 2019 at 16:17:07 UTC, H. S. Teoh wrote:
 Awesome!
 
 It's about time dmd error messages got a facelift.  Will
 -verrors=context eventually become the default?
Yes, I hope so! Once it has gotten a fair bit of real-world feedback and testing (which is the one of the reasons why I opened this thread) we can enable it by default if a TTY is detected. TTY detection is probably necessary as there are still a lot of programs (especially editor plugins) which parse the DMD output.
[...] Seriously, for editor/IDE plugins, there should be a --porcelain option that outputs error messages in a machine-friendly format, like with a fixed format that's easy for scripts / code / whatever to parse. T -- Life is too short to run proprietary software. -- Bdale Garbee
Jan 12
parent reply Seb <seb wilzba.ch> writes:
On Saturday, 12 January 2019 at 16:32:43 UTC, H. S. Teoh wrote:
 Seriously, for editor/IDE plugins, there should be a 
 --porcelain option that outputs error messages in a 
 machine-friendly format, like with a fixed format that's easy 
 for scripts / code / whatever to parse.


 T
It probably would be -verrors=json (or sth. like this), but the problem is that tools which parse DMD output are already out there, so we need to be a bit careful not to break them. Anyhow, I think using TTY detection to enable -verrors=context by default should work fine. DMD did/does the same when color-coded messages (`-color` ) where introduced.
Jan 12
parent WebFreak001 <d.forum webfreak.org> writes:
On Saturday, 12 January 2019 at 16:52:28 UTC, Seb wrote:
 On Saturday, 12 January 2019 at 16:32:43 UTC, H. S. Teoh wrote:
 Seriously, for editor/IDE plugins, there should be a 
 --porcelain option that outputs error messages in a 
 machine-friendly format, like with a fixed format that's easy 
 for scripts / code / whatever to parse.


 T
It probably would be -verrors=json (or sth. like this), but the problem is that tools which parse DMD output are already out there, so we need to be a bit careful not to break them. Anyhow, I think using TTY detection to enable -verrors=context by default should work fine. DMD did/does the same when color-coded messages (`-color` ) where introduced.
I would be happy to change code-d and tools to any other format than currently parsing regexes, it's also missing consecutive errors like "instantiated from here" right now which I would like to fix :)
Jan 14
prev sibling next sibling parent reply viniarck <viniarck gmail.com> writes:
On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
 tl;dr: I was annoyed for years that D's assert are so non 
 informative AssertError, so here's my late Christmas present 
 for the D community. With 2.085 DMD will gain an experimental 
 flag for more informative assertion errors. Feedback on this 
 experimental feature is welcome, s.t. we eventually can enable 
 it by default.

 [...]
Epic! That's massively useful. I Such a great start for D in 2019 :) Thanks a lot, Seb! I'll use this new version soon.
Jan 12
parent viniarck <viniarck gmail.com> writes:
On Saturday, 12 January 2019 at 16:28:57 UTC, viniarck wrote:
 On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
 tl;dr: I was annoyed for years that D's assert are so non 
 informative AssertError, so here's my late Christmas present 
 for the D community. With 2.085 DMD will gain an experimental 
 flag for more informative assertion errors. Feedback on this 
 experimental feature is welcome, s.t. we eventually can enable 
 it by default.

 [...]
Epic! That's massively useful. I Such a great start for D in 2019 :) Thanks a lot, Seb! I'll use this new version soon.
My bad for the typo. I meant to type "It's such a great start for D in 2019".
Jan 12
prev sibling next sibling parent Dennis <dkorpel gmail.com> writes:
On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
 Merry Christmas!
Amazing. I saw the PR a while back and was afraid it would be pushed aside in favor of library solutions, but whenever I quickly write unittests for my modules I never feel like dragging in a fluent assert library and end up manually putting writeln's everywhere, so I'm super glad it's actually coming to dmd.
Jan 12
prev sibling next sibling parent Meta <jared771 gmail.com> writes:
On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
 tl;dr: I was annoyed for years that D's assert are so non 
 informative AssertError, so here's my late Christmas present 
 for the D community. With 2.085 DMD will gain an experimental 
 flag for more informative assertion errors. Feedback on this 
 experimental feature is welcome, s.t. we eventually can enable 
 it by default.

 Example:

 ---
 void main()
 {
     int a = 1, b = 2;
     assert(a == b); // ERROR: 1 != 2
 }
 ---

 ```
 dmd -run onlineapp.d
core.exception.AssertError onlineapp.d(4): 1 != 2 ---------------- ??:? _d_assert_msg [0xb150e350] ??:? _Dmain [0xb150d627] ``` Play online: https://run.dlang.io/is/GMfe9S Full changelog: https://dlang.org/changelog/pending.html#assert Where to start hacking: - https://github.com/dlang/dmd/blob/00299e3b6ca9dcd5a5dc8bd50280b63d0bdc51f9/src/dmd/expressionsem.d#L5559 - https://github.com/dlang/druntime/blob/master/src/core/internal/dassert.d - https://github.com/dlang/dmd/pull/8517 Q: Why not just introduce an `assertEqual` user function? A: - there's a lot of already written D code out there that uses `assert` [1] - `assertEqual` wouldn't cut, it because then we would need to have an `assertLessThan` etc. too Q: Why put this in the compiler and not in fluent-assert or similar library? A: - there's a lot of already written D code out there that uses `assert` [1] - not everyone wants to use a library just to have somewhat decent assert messages - libraries can only do sth. like `testedValue.should.equal(42)`, but the compiler can deal with `testedValue == 42` [1] https://github.com/search?l=D&q=assert&type=Code Error context ------------- Also note that with 2.085 DMD will get -verrors=context --- void foo() { a = 1; } --- ```
 dmd -verrors=context onlineapp.d
onlineapp.d(3): Error: undefined identifier a a = 1; ^ ``` Full changelog: https://dlang.org/changelog/pending.html#error-context Play online: https://run.dlang.io/is/8gsye1 Thanks to all the people (Jacob Carlborg, Petar Kirov, Nicolas Wilson, Rainer Schuetze, etc.) who helped me to get this feature into DMD! Merry Christmas!
Thank you so much for working on this. There's nothing more infuriating than my program crashing due to a failed assert, then having to edit and recompile it just to put in some debug printing. It's not a big problem when I take the time to do things properly and put the relevant information into the assert message, but when I'm quickly hacking on some code it's annoying to do it for every single assert (I generally use asserts and DBC religiously to ensure preconditions and assumptions actually hold). This is one of those little things that is so small but is also extremely annoying, so thank you again for taking the time to fix it.
Jan 12
prev sibling next sibling parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
 Full changelog: 
 https://dlang.org/changelog/pending.html#error-context
 Play online: https://run.dlang.io/is/8gsye1

 Thanks to all the people (Jacob Carlborg, Petar Kirov, Nicolas 
 Wilson, Rainer Schuetze, etc.) who helped me to get this 
 feature into DMD!
Wonderful! Have you looked at my previous proposal at https://wiki.dlang.org/DIP83? Thanks a lot!
Jan 13
parent Seb <seb wilzba.ch> writes:
On Sunday, 13 January 2019 at 09:48:53 UTC, Per Nordlöw wrote:
 Have you looked at my previous proposal at 
 https://wiki.dlang.org/DIP83?
Yes of course ;-) (and it was one of the main inspirations for this work). Please see the DMD PR for the full history of this feature, discussion and the implementation in DMD: https://github.com/dlang/dmd/pull/8517
Jan 13
prev sibling next sibling parent reply Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
 https://dlang.org/changelog/pending.html#error-context
 Play online: https://run.dlang.io/is/8gsye1
Is there a way to download a dmd nightly and try this out? The nightly at https://dlang.org/download.html is currently broken.
Jan 13
parent reply Seb <seb wilzba.ch> writes:
On Sunday, 13 January 2019 at 11:11:05 UTC, Per Nordlöw wrote:
 On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
 https://dlang.org/changelog/pending.html#error-context
 Play online: https://run.dlang.io/is/8gsye1
Is there a way to download a dmd nightly and try this out?
e.g. https://run.dlang.io/is/GMfe9S for playing online with it. or: curl https://dlang.org/install.sh | bash -s dmd-nightly
 The nightly at https://dlang.org/download.html is currently 
 broken.
The link just uses HTTPS which isn't supported by the S3 bucket. HTTP works: HTTP works: http://downloads.dlang.org/nightlies/ See also: https://github.com/dlang/dlang.org/pull/2554 Alternatively, you could always use digger: --- dub fetch digger dub run digger -- build --- (this will build the current master of DMD/Druntime/Phobos/Tools/Dub automatically for you)
Jan 13
parent Per =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
On Sunday, 13 January 2019 at 12:01:49 UTC, Seb wrote:
 The link just uses HTTPS which isn't supported by the S3 bucket.
 HTTP works: HTTP works: http://downloads.dlang.org/nightlies/

 See also: https://github.com/dlang/dlang.org/pull/2554

 Alternatively, you could always use digger:

 ---
 dub fetch digger
 dub run digger -- build
 ---

 (this will build the current master of 
 DMD/Druntime/Phobos/Tools/Dub automatically for you)
Thanks!
Jan 13
prev sibling next sibling parent Vladimir Panteleev <thecybershadow.lists gmail.com> writes:
On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
 Thanks to all the people (Jacob Carlborg, Petar Kirov, Nicolas 
 Wilson, Rainer Schuetze, etc.) who helped me to get this 
 feature into DMD!

 Merry Christmas!
Awesome, thank you! This should be great for debug builds.
Jan 13
prev sibling next sibling parent reply Atila Neves <atila.neves gmail.com> writes:
On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
 tl;dr: I was annoyed for years that D's assert are so non 
 informative AssertError, so here's my late Christmas present 
 for the D community. With 2.085 DMD will gain an experimental 
 flag for more informative assertion errors. Feedback on this 
 experimental feature is welcome, s.t. we eventually can enable 
 it by default.

 [...]
Awesome. It's obvious that assertions for equality are the most common, I wonder how easy it would be to get other changes merged like `assert(foo in bar)`. There are also all the assertions that make use of `equal` because of ranges. In unit-threaded `foo.should == bar` works if foo is a range and bar is a dynamic array. What I'd really like is access to the AST in the assert but alas I don't think that will ever be possible.
Jan 14
parent Seb <seb wilzba.ch> writes:
On Monday, 14 January 2019 at 14:15:45 UTC, Atila Neves wrote:
 On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
 tl;dr: I was annoyed for years that D's assert are so non 
 informative AssertError, so here's my late Christmas present 
 for the D community. With 2.085 DMD will gain an experimental 
 flag for more informative assertion errors. Feedback on this 
 experimental feature is welcome, s.t. we eventually can enable 
 it by default.

 [...]
Awesome. It's obvious that assertions for equality are the most common, I wonder how easy it would be to get other changes merged like `assert(foo in bar)`.
Should be easy enough: https://github.com/dlang/dmd/pull/9264 https://github.com/dlang/druntime/pull/2463 Also note that other trivial stuff like `a < b` is already supported. See e.g.: https://github.com/dlang/druntime/blob/master/test/exceptions/src/assert_fail.d
 There are also all the assertions that make use of `equal` 
 because of ranges.
In theory we could hard-code a check for the symbol in DMD and see whether its std.algorithm.comparison.equal, but ranges are tricky as both might have been consumed by `equal` and you would then end up printing e.g. sth. like: [] != []
 I'd really like is access to the AST in the assert but alas I 
 don't think that will ever be possible.
Yeah :/
Jan 14
prev sibling next sibling parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 1/12/19 10:34 AM, Seb wrote:
 tl;dr: I was annoyed for years that D's assert are so non informative 
 AssertError, so here's my late Christmas present for the D community. 
 With 2.085 DMD will gain an experimental flag for more informative 
 assertion errors. Feedback on this experimental feature is welcome, s.t. 
 we eventually can enable it by default.
 
 Example:
 
 ---
 void main()
 {
      int a = 1, b = 2;
      assert(a == b); // ERROR: 1 != 2
 }
 ---
 
 ```
 dmd -run onlineapp.d
core.exception.AssertError onlineapp.d(4): 1 != 2
Wonderful. Thanks!
Jan 14
prev sibling next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 1/12/19 10:34 AM, Seb wrote:
 tl;dr: I was annoyed for years that D's assert are so non informative 
 AssertError, so here's my late Christmas present for the D community. 
 With 2.085 DMD will gain an experimental flag for more informative 
 assertion errors. Feedback on this experimental feature is welcome, s.t. 
 we eventually can enable it by default.
[...]
 Thanks to all the people (Jacob Carlborg, Petar Kirov, Nicolas Wilson, 
 Rainer Schuetze, etc.) who helped me to get this feature into DMD!
 
 Merry Christmas!
Just want to add in my +1. Thanks! -Steve
Jan 14
prev sibling next sibling parent reply Kagamin <spam here.lot> writes:
On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
 void main()
 {
     int a = 1, b = 2;
     assert(a == b); // ERROR: 1 != 2
 }
But 1!=2 is true :) Maybe do it the C way "assertion 1 == 2 failed"? Also there's in operator.
Jan 15
parent reply Seb <seb wilzba.ch> writes:
On Tuesday, 15 January 2019 at 08:43:06 UTC, Kagamin wrote:
 On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
 void main()
 {
     int a = 1, b = 2;
     assert(a == b); // ERROR: 1 != 2
 }
But 1!=2 is true :) Maybe do it the C way "assertion 1 == 2 failed"? Also there's in operator.
Hmm you have a point there. How do other people feel about this? My main motivation was to be able to see the actual values (instead of just an AssertError), so I would be more than happy to change the format of the message.
Jan 15
next sibling parent Kagamin <spam here.lot> writes:
On Tuesday, 15 January 2019 at 10:23:32 UTC, Seb wrote:
 My main motivation was to be able to see the actual values 
 (instead of just an AssertError), so I would be more than happy 
 to change the format of the message.
I remember Adam wanted the asserted expression to be printed as is to more reliably locate the failed assert as it can move when the code changes. Did you consider it? So the message can be "assertion a == b failed: a=1,b=2".
Jan 15
prev sibling next sibling parent rjframe <dlang ryanjframe.com> writes:
On Tue, 15 Jan 2019 10:23:32 +0000, Seb wrote:

 On Tuesday, 15 January 2019 at 08:43:06 UTC, Kagamin wrote:
 On Saturday, 12 January 2019 at 15:34:02 UTC, Seb wrote:
 void main()
 {
     int a = 1, b = 2;
     assert(a == b); // ERROR: 1 != 2
 }
But 1!=2 is true :) Maybe do it the C way "assertion 1 == 2 failed"? Also there's in operator.
Hmm you have a point there. How do other people feel about this? My main motivation was to be able to see the actual values (instead of just an AssertError), so I would be more than happy to change the format of the message.
I think I'd agree with Kagamin - after the first time you'd know it, but D already has a big list of "after the first time" features; If we see D-learners posting, confused about it, then it should probably be adjusted; otherwise, maybe it's not a major concern. I just skimmed some of my tests and the current message works, but may take some getting used to because of the reversal of the conditional. Ex: assert(opts.imports[0] == "std.stdio"); // becomes "ERROR: std.file != std.stdio"... well, yeah. // "ERROR: assertion std.file == std.stdio failed" is an easier read // (at least for me) --Ryan
Jan 15
prev sibling parent Jacob Carlborg <doob me.com> writes:
On 2019-01-15 11:23, Seb wrote:

 Hmm you have a point there. How do other people feel about this?
I think the message should look as similar as the expression in the code as possible. -- /Jacob Carlborg
Jan 15
prev sibling parent reply Kagamin <spam here.lot> writes:
And what happens to other expressions?

assert(a == b); // ERROR: 1 != 2
assert(c.has(d)); // ERROR: c.has(d)

The message will have an opposite meaning?
Jan 15
parent Seb <seb wilzba.ch> writes:
On Tuesday, 15 January 2019 at 08:47:24 UTC, Kagamin wrote:
 And what happens to other expressions?
..
 assert(c.has(d)); // ERROR: c.has(d)

 The message will have an opposite meaning?
https://run.dlang.io/is/mRQM02 --- core.exception.AssertError onlineapp.d(5): assert(a.has(b)) failed ---------------- ??:? _d_assert_msg [0x2bf174b4] ??:? _Dmain [0x2bf173ed] --- It falls back to printing the stringified raw expression as the changelog states [1]. (this is still an improvement compared to the current "AssertError" without any information) [1] https://dlang.org/changelog/pending.html#assert
Jan 15