November 19, 2022

On Saturday, 19 November 2022 at 08:11:45 UTC, Dukc wrote:

>

On Friday, 18 November 2022 at 12:36:14 UTC, RazvanN wrote:

>

What do you think? Is deprecating having an assert message that may throw a severe restriction? Are there other rewrites that I am missing?

In my opinion the fix is clear. When the assertion handler at DRuntime determines the assertion has failed, it should call the error message generator (it is lazy IIRC) in a try/catch block. If the generator throws an exception, the error message of assertion failure should be something like <FormatException thrown while writing error message>.

Should the error generation exception be the .next member of AssertError? Probably, but I'm not sure.

If the message generator throws an unrecoverable error, that should probably still mask the assert error. If a RangeError masks AssertError it's unlikely to be a problem since neither is likely to be caught and at least in my mind they're essentially the same - a "bug detected" error.

I agree with what you are saying. It think it is essentially what I wrote above but writing a better error message than I suggested.

November 19, 2022
On 11/18/22 13:36, RazvanN wrote:
> Is deprecating having an assert message that may throw a severe restriction?

Yes.

November 19, 2022
On 11/18/22 13:36, RazvanN wrote:
> 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)
>         );
> ```

Please don't just swallow the exception and error message. This particular fix is worse than the problem.

November 20, 2022
On 11/18/22 05:06, Patrick Schluter wrote:

> It's a bug in the program that has
> to be corrected in any case. When it is corrected, the assert() will
> manifest itself and can then be corrected also. When debugging a
> program, I always concentrate on the first error/bug/exception as very
> often subsequent errors/bugs/exceptions were more often than not just
> consequences of undefined behaviour of the initial error.

I am in the habit of catching Exceptions in main() to print a human-friendly error message because those are just messages that the users should know about. Which means, the backtrace is missing for Exceptions.

In contrast, although embarrassing, I let Errors uncaught so the default behaviour of dumping the backtrace is preserved.

For that reason, this issue may hide useful information about bugs that are observed only be a user.

Ali

November 20, 2022
On 11/18/22 14:05, Walter Bright wrote:

>> So just write:
>>
>>          assert(myAssumption, format!"%s doesn't work!"(blah));
>>
>> Problem solved.
>
> You should post that to the bug report!

The problem with the format string was just an example. What if 'blah' above is a function that throws Exception?

Ali

November 20, 2022
On 11/19/22 00:11, Dukc wrote:

> In my opinion the fix is clear.
[...]
> Should the error generation exception be the `.next` member of
> `AssertError`? Probably, but I'm not sure.

I think the following is what you describe:

import std;

void assertImpl_(string file = __FILE__, size_t line = __LINE__)(bool value, lazy string msgGen) {
    if (!value) {
        string msg;
        Throwable next;

        try {
            msg = msgGen;

        } catch (Exception exc) {
            msg = "(Additionally failed to generate the assertion failure message.)";
            next = exc;
        }

        import core.exception : AssertError;
        throw new AssertError(msg, file, line, next);
    }
}

void main() {
    // This passes through despite the error in the message:
    assertImpl_(true, format("%s"));

    // This throws AssertError where the message formatting
    // is a collateral Throwable:
    assertImpl_(false, format("%s"));
}

Discussion: As I commented on the bug report as well, D is already in the best-effort business when it comes to Errors:

1) If the assert expression *will* fail, the program is already in an invalid state. (I claim, it is not a failed assert expression that puts the program into invalid state; rather, the fact that the expression will fail.)

So, even evaluating the assert expression is best-effort.

2) The default behavior for the main thread is to catch Error and dump backtrace to stderr. That is best-effort because now we are catching an Error.

Given the above two observations, the code inside 'if (!value)' above should also be considered best-effort and I think is the solution for this bug.

The only thing that bothers me is the 'lazy' parameter which I think is a 'delegate'. Perhaps the compiler can use a 'function' lazily there. (?)

Ali

November 24, 2022
On Sunday, 20 November 2022 at 18:30:00 UTC, Ali Çehreli wrote:
> On 11/19/22 00:11, Dukc wrote:
>
> > In my opinion the fix is clear.
> [...]
> > Should the error generation exception be the `.next` member of
> > `AssertError`? Probably, but I'm not sure.
>
> I think the following is what you describe:

If we can come up with our own solutions, we shouldn't expect a solution from D. The observations are fine.

Thank you...

SDB@79
November 24, 2022

On Friday, 18 November 2022 at 13:18:39 UTC, Dennis wrote:

>

My thoughts:

  • A wrong format string passed to format should be a runtime error (if not caught at compile time), not an exception

I don't think it should be an error.

Format strings could come from user code and it shouldn't break the whole application because a user put a wrong format string in.

This is especially important in applications that can have multiple users interacting with it at the same time ex. a website, game server etc.

If it should be an error then there should be a way to validate a format string at runtime without attempting to call format.

Error should only be used for errors that aren't recoverable ex. out of memory, stackoverflow etc. it shouldn't be used for errors that are recoverable, that's exactly what exception is for.

November 24, 2022

On Thursday, 24 November 2022 at 08:23:22 UTC, bauss wrote:

>

Format strings could come from user code

Can you name one application that does this?

>

This is especially important in applications that can have multiple users interacting with it at the same time ex. a website, game server etc.

I've never seen a website or game ask me to input a programming language-specific format string.

>

If it should be an error then there should be a way to validate a format string at runtime without attempting to call format.

Yes, I agree.

>

Error should only be used for errors that aren't recoverable

True, but what you consider recoverable is a subjective design decision.

>

ex. out of memory

Can be recoverable. If I try to render a scene in Blender that's too complex for my GPU, it reports 'out of memory' without closing the program.

But considering out of memory is unrecoverable by default in D, you can get in trouble when the user gives you a format string that generates very large output, such as "%2000000000s", so currently it's not safe to use format strings provided from user input anyway.

November 25, 2022

On Sunday, 20 November 2022 at 18:30:00 UTC, Ali Çehreli wrote:

>

On 11/19/22 00:11, Dukc wrote:

>

In my opinion the fix is clear.
[...]
Should the error generation exception be the .next member of
AssertError? Probably, but I'm not sure.

I think the following is what you describe:

[snip]

Yes, that's correct.

>

Discussion: As I commented on the bug report as well, D is already in the best-effort business when it comes to Errors:

What does "best-effort" mean?