Program logic bugs vs input/environmental errors

Walter Bright via Digitalmars-d digitalmars-d at puremagic.com
Sun Nov 2 22:03:33 PST 2014


On 11/2/2014 8:54 PM, Sean Kelly wrote:
> On Monday, 3 November 2014 at 03:29:05 UTC, Walter Bright wrote:
>> I got into the habit of layering in asserts to stop the program when it went
>> bad. "Do not pass go, do not collect $200" is the only strategy that has a
>> hope of working under such systems.
> The tough thing is that in D, contracts serve as this early warning system, but
> the errors this system catches are also sometimes benign

If it is benign is not known until it is debugged by a human.

> and sometimes the
> programmer knows that they're benign, but if the person writing the test did so
> with an assert then the decision of how to respond to the error has been made
> for him.

The person who wrote "assert" decided that it was a non-recoverable programming 
bug. I deliberately wrote "bug", and not "error".


>> It is my duty to explain how to use the features of the language correctly,
>> including how and why they work the way they do. The how, why, and best
>> practices are not part of a language specification.
> I don't entirely agree.  The standard library serves as the how and how and best
> practices for a language, and while a programmer can go against this, it's often
> like swimming upstream.  For better or worse, we need to establish how
> parameters are validated and such in Phobos, and this will serve as the template
> for nearly all code written in D.

Definitely Phobos should exhibit best practices. Whether bad function argument 
values are input/environmental errors or bugs is decidable only on a 
case-by-case basis. There is no overarching rule.

Input/environmental errors must not use assert to detect them.


> To be fair, assert currently does unwinding.  It always has.  The proposal is
> that it should not.

Not entirely - a function with only asserts in it is considered "nothrow" and 
callers may not have exception handlers for them.


>> The reason I initiated this thread is to point out the correct way to use
>> assert() and to get that into the culture of best practices for D. This is
>> because if I don't, then in the vacuum people will tend to fill that vacuum
>> with misunderstandings and misuse.
>>
>> It is an extremely important topic.
>
> I still feel like there's something really important here that we're all
> grasping at but it hasn't quite come to the fore yet. Along the lines of the
> idea that a @safe program may be able to recover from a logic error.  It seems
> like a uniquely D thing insofar as systems languages are concerned.

It's a false hope. D cannot offer any guarantees of recovery from programming 
bugs. Asserts, by definition, can never happen. So when they do, something is 
broken. Broken programs are not recoverable because one cannot know why they 
broke until they are debugged. As I mentioned to Dicebot, @safe only applies to 
the function's logic. D programs can call C functions. C functions are not safe. 
There can be compiler bugs. There can be other threads corrupting memory. There 
can be hardware failures, operating system bugs, etc., that resulting in 
tripping the assert.

If a programmer "knows" a bug is benign and wants to recover from it, D has a 
mechanism for it - enforce(). I do not understand the desire to bash assert() 
into behaving like enforce(). Just use enforce() in the first place.

The idea was brought up that one may be using a library that uses assert() to 
detect input/environmental errors. I do not understand using a library in a 
system that must be made robust, having the source code to the library, and not 
being allowed to change that source code to fix bugs in it. A robust application 
cannot be made using such a library - assert() misuse will not be the only 
problem with it.


>> If the operating system can't handle resource recovery for a process
>> terminating, it is an unusable operating system.
> There are all kinds of resources, and not all of them are local to the system.
> Everything will eventually recover though, it just won't happen immediately as
> is the case with resource cleanup within a process.

I'd say that is a poor design for an operating system. Be that as it may, if you 
want to recover from assert()s, use enforce() instead.


There are other consequences from trying to make assert() recoverable:

1. functions with assert()s cannot be "nothrow"
2. assert()s cannot provide hints to the optimizer

Those are high prices to pay for a systems performance language.


More information about the Digitalmars-d mailing list