www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - assert with format considered harmful

reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
If the generation of the error message throws, then the program receives 
a FormatException, not the most import AssertError:

import std.string;

void foo(int i) {
     // In this case a %s is forgotten but it could be any other trivial 
error.
     assert(i == 42, format("Bad parameter:", i));
}

void main() {
     foo(43);
}

Opened:

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

So, obviously, assert message generation is not lazy. This is a WAT! for 
me but perhaps there is a good reason for it.

Google found a related article by Peter Alexander:

   http://poita.org/2012/09/02/a-better-assert-for-d.html

Ali
Feb 25 2017
next sibling parent reply Seb <seb wilzba.ch> writes:
On Sunday, 26 February 2017 at 06:34:07 UTC, Ali Çehreli wrote:
 So, obviously, assert message generation is not lazy. This is a 
 WAT! for me but perhaps there is a good reason for it.
FWIW imho we shouldn't need to write such messages at all. It shouldn't be to difficult to lower `assert (a BINOP b)` into sth. like: (auto ref a, auto ref b) { if (a BINOP b) return; onAssertFailed!"BINOP"(a, b, __FILE__, __LINE__, __FUNCTION__, __MODULE__); } (e1, e2); with onAssertFailed being a nice pretty-printer in the direction of: assert([1,2,3] == [1,2,4]); // ERROR: ([1,2,3][2] is 3) != ([1,2,4][2] is 4) struct A { int x, y; } auto a = A(1,2); auto b = A(1,3); assert(a == b); // ERROR: (a.y is 2) != (b.y is 3) This idea is formally known as DIP83: https://wiki.dlang.org/DIP83
Feb 25 2017
next sibling parent ketmar <ketmar ketmar.no-ip.org> writes:
Seb wrote:

 On Sunday, 26 February 2017 at 06:34:07 UTC, Ali Çehreli wrote:
 So, obviously, assert message generation is not lazy. This is a WAT! 
 for me but perhaps there is a good reason for it.
FWIW imho we shouldn't need to write such messages at all. It shouldn't be to difficult to lower `assert (a BINOP b)` into sth. like: (auto ref a, auto ref b) { if (a BINOP b) return; onAssertFailed!"BINOP"(a, b, __FILE__, __LINE__, __FUNCTION__, __MODULE__); } (e1, e2); with onAssertFailed being a nice pretty-printer in the direction of: assert([1,2,3] == [1,2,4]); // ERROR: ([1,2,3][2] is 3) != ([1,2,4][2] is 4) struct A { int x, y; } auto a = A(1,2); auto b = A(1,3); assert(a == b); // ERROR: (a.y is 2) != (b.y is 3) This idea is formally known as DIP83: https://wiki.dlang.org/DIP83
or at least print the condition that failed, if there is no assert message. this patch alone saved me alot of brain cells. somehow it is way easier for me to look at stack trace and get "aha!" moment, than to look at the source line with assert. even if the info is exactly the same. ;-) besides, assert with condition printed simply looks better. note that your suggestion may require calling `toString()`, which may allocate, and it may be undesirable to allocate there (maybe programmer did't printed more detailed info exactly 'cause he wanted to avoid possible allocations?). and condition printing done by simply adding pretty-printed string in frontend.
Feb 26 2017
prev sibling parent reply "Nick Sabalausky (Abscissa)" <SeeWebsiteToContactMe semitwist.com> writes:
On 02/26/2017 02:17 AM, Seb wrote:
 On Sunday, 26 February 2017 at 06:34:07 UTC, Ali Çehreli wrote:
 So, obviously, assert message generation is not lazy. This is a WAT!
 for me but perhaps there is a good reason for it.
FWIW imho we shouldn't need to write such messages at all. It shouldn't be to difficult to lower `assert (a BINOP b)` into sth. like: (auto ref a, auto ref b) { if (a BINOP b) return; onAssertFailed!"BINOP"(a, b, __FILE__, __LINE__, __FUNCTION__, __MODULE__); } (e1, e2); with onAssertFailed being a nice pretty-printer in the direction of: assert([1,2,3] == [1,2,4]); // ERROR: ([1,2,3][2] is 3) != ([1,2,4][2] is 4) struct A { int x, y; } auto a = A(1,2); auto b = A(1,3); assert(a == b); // ERROR: (a.y is 2) != (b.y is 3) This idea is formally known as DIP83: https://wiki.dlang.org/DIP83
Yea. Six years ago, assertPred was written for Phobos and rejected because it was decided it was better for assert to just gain that functionality built-in...which a full six years later, never happened. Letting perfect be the enemy of the good, at its golden finest.
Feb 26 2017
next sibling parent Seb <seb wilzba.ch> writes:
On Sunday, 26 February 2017 at 16:13:47 UTC, Nick Sabalausky 
(Abscissa) wrote:
 On 02/26/2017 02:17 AM, Seb wrote:
 [...]
Yea. Six years ago, assertPred was written for Phobos and rejected because it was decided it was better for assert to just gain that functionality built-in...which a full six years later, never happened. Letting perfect be the enemy of the good, at its golden finest.
Well if it makes you feel any better, I had a similar experience last summer: https://github.com/dlang/phobos/pull/4323 (the same opinion prevailed)
Feb 26 2017
prev sibling parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Sunday, February 26, 2017 11:13:47 Nick Sabalausky  via Digitalmars-d 
wrote:
 Yea. Six years ago, assertPred was written for Phobos and rejected
 because it was decided it was better for assert to just gain that
 functionality built-in...which a full six years later, never happened.
 Letting perfect be the enemy of the good, at its golden finest.
Well, to make matters more entertaining, it was later decided that it was unreasonable to alter assert to print the extra information that assertPred had. So, it's not even a case of no one doing it. It's a case of it being rejected, leaving us with neither solution. - Jonathan M Davis
Feb 26 2017
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
Let me point out the elephant in the room as well.

On 02/25/2017 10:34 PM, Ali Çehreli wrote:

     // In this case a %s is forgotten but it could be any other trivial
 error.
     assert(i == 42, format("Bad parameter:", i));
In addition to the current dangerous behavior of assert, there is the philosophical argument whether the program can do anything at all after an assert. Like many others, our friend Chris Wright thinks so: http://forum.dlang.org/post/o6u5j5$1gnf$1 digitalmars.com On the other hand, I, like many others, have apparently been hypocritical every time I attempted to generate a message for assert. That's wishful coding indeed. :) How about this rule: The message generation code must be - be nothrow - have no side-effects, which means the message that it generates must be written into a pre-allocated space, without going out of bounds (how to control this?) - nogc (I think this is implied from the previous two) The more I learn and understand about computing the more it becomes crazy. :) Ali
Feb 27 2017