What should happen when the assert message expression throws?
RazvanN
razvan.nitu1305 at gmail.com
Fri Nov 18 12:36:14 UTC 2022
I have stumbled upon:
https://issues.dlang.org/show_bug.cgi?id=17226
I want to fix it, however, the solution is not obvious.
Take this code:
```d
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);
}
```
If `format` throws, then the Exception is thrown masking the
assert error.
Unfortunately, I don't see a clear way to rewrite this to valid D
code as to catch the exception and then assert. Ideally, we could
do something along the lines of:
```d
assert(i == 42,
(const(char)[] msg,
try { msg = format("Bad parameter:", i); },
catch (Exception e) { msg = "Assert message evaluation
has failed";},
msg)
);
```
This rewrite would be done only if it is determined that the
assert message may throw. However, the current dmd-fe
implementation does not allow for such a construction and I think
that it might be overkill to implement the necessary machinery
just to support this case.
The try catch block can also be generated outside of the assert
expression:
```d
auto msg;
try { msg = format("Bad parameter:", i);}
catch (Exception e) { msg = "Assert message evaluation has
failed";}
assert(i == 42, msg);
```
The difference between the 2 is that in this case we are
evaluating the msg regardless of whether the assert condition is
true or false.
Also, we need to take into account the case where the user tries
to catch the exception by himself:
```d
void foo(int i)
{
try
{
// In this case a %s is forgotten but it could be any
other trivial error.
assert(i == 42, format("Bad parameter:", i));
}
catch(Exception e) { /* do some sort of fix up with the
message */}
}
void main()
{
foo(43);
}
```
Today, this code runs successfully and no AssertError is thrown.
If we automatically catch the exception we might break such code
(although I would argue it would not be too dramatic).
An alternative solution would be to deprecate having an assert
message that may throw. This has the advantage that it avoids
complexity inside the compiler and the user is forced to write:
```d
auto msg = /* do whatever you want with throwing code */
assert(cond, msg);
```
If the user wants to catch the exception or not, it's his/hers
business, but then the compiler has defined semantics in all
situations.
What do you think? Is deprecating having an assert message that
may throw a severe restriction? Are there other rewrites that I
am missing?
Cheers,
RazvanN
More information about the Digitalmars-d
mailing list