November 09, 2014
On Friday, 7 November 2014 at 15:00:35 UTC, Bruno Medeiros wrote:
> Very well then. But then we'll get to the point where enforce() will become much more popular than assert to check for contract conditions. assert() will be relegated to niche and rare situations where the program cant really know how to continue/recover cleanly (memory corruption for example).
>
> That idiom is fine with me actually - but then the documentation for assert should reflect that.

This looks like a only practical solution for me right now - but it is complicated by the fact that assert is not the only Error in the library code.
November 09, 2014
On 11/7/2014 7:00 AM, Bruno Medeiros wrote:
> Let me give an example:
>
> double sqrt(double num) {
>    assert(num >= 0);
>    ...
>
> With just this, then purely from a compiler/language viewpoint, if the assert is
> triggered the *language* doesn't know if the whole program is corrupted
> (formatting the hard disk, etc.), or if the fault is localized there, and an
> error/exception can be thrown cleanly (clean in the sense that other parts of
> the program are not corrupted).
>
> So the language doesn't know, but the *programmer* can make a reasoning in each
> particular assert of which domains/components of the program are affected by
> that assertion failure. In the sqrt() case above, the programmer can easily
> state that the math library that sqrt is part of is not corrupted, and its state
> is not totally unknown (as in, it's not deadlocked, nor is it formatting the
> hard disk!).

Making such an assumption presumes that the programmer knows the SOURCE of the bug. He does not. The source could be a buffer overflow, a wild pointer, any sort of corruption.


> Very well then. But then we'll get to the point where enforce() will become much
> more popular than assert to check for contract conditions. assert() will be
> relegated to niche and rare situations where the program cant really know how to
> continue/recover cleanly (memory corruption for example).
>
> That idiom is fine with me actually - but then the documentation for assert
> should reflect that.

I created this thread because it is an extremely important topic. It has come up again and again for my entire career.

There is no such thing as knowing in advance what caused a bug, and that the bug is "safe" to continue from. If you know in advance what caused it, then it becomes expected program behavior, and is not a bug.

assert() is for bug detection, detecting state that should have never happened. By definition you cannot know it is "safe", you cannot know what caused it.

enforce() is for dealing with known, expected conditions.
November 09, 2014
On 11/9/2014 1:12 PM, Dicebot wrote:
> On Monday, 3 November 2014 at 03:29:05 UTC, Walter Bright wrote:
>> It is absolutely different because of scale; having 1K of shared memory is
>> very different from having 100Mb shared between processes including the stack
>> and program code.
> It is possible to have minimal amount shared mutable memory inside one process.

D's type system tries to minimize it, but the generated code knows nothing at all about the difference between local and shared memory, and has no protection against crossing the boundary. Interprocess protection is done via the hardware.


> There is nothing inherently blocking one to do so, same as there is nothing
> inherently preventing one to screw the inter-process shared memory. Being
> different only because of scale -> not really different.

Sharing 1K of interprocess memory is one millionth of the vulnerability surface of a 1G multithreaded program.


> What is huge advance for user land applciation is a problem for server code.
> Have you ever heard "OS is the problem, not solution" slogan that is slowly
> becoming more popular in high load networking world?

No, but my focus is what D can provide, not what the OS can provide.


> Preventing cleanup can be done with roughly one line of code from user code.
> Enabling it back is effectively impossible. With this decision you don't trade
> safer default for more dangerous default - you trade configurable default for
> unavoidable.
>
> To preserve same safe defaults you could define all thrown Errors to result in
> plain HLT / abort call with possibility to define user handler that actually
> throws. That would have addressed all concernc nicely while still not making
> life of those who want cleanup harder.

There is already a cleanup solution - use enforce().


>> That's correct, but not a justification for making it less reliable.
> It is justification for making it more configurable.

In general, some things shouldn't be configurable. For example, one cannot mix 3rd party libraries when each one is trying to customize global behavior.


> My personal perfect design would be like this:
>
> - Exceptions work as they do now
> - Errors work the same way as exceptions but don't get caught by catch(Exception)
> - assert does not throw Error but simply aborts the program (configurable with
> druntime callback)
> - define "die" which is effectively "assert(false)"
> - tests don't use assert

Having assert() not throw Error would be a reasonable design choice.

November 09, 2014
On Sunday, 9 November 2014 at 21:34:05 UTC, Walter Bright wrote:
> On 11/7/2014 7:00 AM, Bruno Medeiros wrote:

> assert() is for bug detection, detecting state that should have never happened. By definition you cannot know it is "safe", you cannot know what caused it.
>
> enforce() is for dealing with known, expected conditions.

This is clear. The missing piece is a way to make the compile enforce that use on the user.

Code review alone does not work.
November 09, 2014
On Sunday, 9 November 2014 at 21:59:19 UTC, eles wrote:
> On Sunday, 9 November 2014 at 21:34:05 UTC, Walter Bright wrote:
>> On 11/7/2014 7:00 AM, Bruno Medeiros wrote:
>
>> assert() is for bug detection, detecting state that should have never happened. By definition you cannot know it is "safe", you cannot know what caused it.
>>
>> enforce() is for dealing with known, expected conditions.
>
> This is clear. The missing piece is a way to make the compile enforce that use on the user.
>
> Code review alone does not work.

This is clear. The missing piece is a way to make the compiler
enforce that separate use on the user.

Code review alone does not work.
November 11, 2014
On Saturday, 1 November 2014 at 16:42:31 UTC, Walter Bright wrote:
> My ideas are what are implemented on airplanes.

For components, not for a system. Nobody said a word against component design, it's systems that people want to be able to design, yet you prohibit it.

> I didn't originate these ideas, they come from the aviation industry.

You're original in claiming it is the only working solution, but aviation industry proves error resilient systems are possible and successful, even though you claim their design is unsound and unusable. Yet you praise them, acknowledging their success, which makes your claims ever so ironical.

> Recall that I was employed as an engineer working on flight critical systems design for the 757.

This is how problem decomposition works: you don't need to understand the whole system to work on a component.

On Sunday, 2 November 2014 at 17:53:45 UTC, Walter Bright wrote:
> Kernel mode code is the responsibility of the OS system, not the app.

Suddenly safety becomes not the top priority. If it can't always be the priority, there should be a choice of priorities, but you deny that choice. It's a matter of compliance with reality. Whatever way you design the language, can you change reality that way? I don't see why possibility of choice prevents anything.
November 12, 2014
On Sunday, 9 November 2014 at 21:44:53 UTC, Walter Bright wrote:
> Having assert() not throw Error would be a reasonable design choice.

What if you could turn assert() in libraries into enforce() using a compiler switch?

Servers should be able to record failure and free network resources/locks even on fatal failure.



November 12, 2014
On the other hand I guess HLT will signal SIGSEGV which can be caught using a signal handler, but then D should provide the OS-specific infrastructure for obtaining the necessary information before exiting.
November 12, 2014
On 11/12/2014 11:40 AM, "Ola Fosheim Grøstad" <ola.fosheim.grostad+dlang@gmail.com>" wrote:
> On Sunday, 9 November 2014 at 21:44:53 UTC, Walter Bright wrote:
>> Having assert() not throw Error would be a reasonable design choice.
>
> What if you could turn assert() in libraries into enforce() using a compiler
> switch?

Forgive me for being snarky, but there are text editing utilities where one can:

   s/assert/enforce/

because if one can use a compiler switch, then one has the source which can be edited.

In any case, compiler switches should not change behavior like that. assert() and enforce() are completely different.
November 12, 2014
On Wednesday, 12 November 2014 at 20:40:45 UTC, Walter Bright wrote:
> Forgive me for being snarky, but there are text editing utilities where one can:

Snarky is ok. :)

> In any case, compiler switches should not change behavior like that. assert() and enforce() are completely different.

Well, but I don't understand how assert() can unwind the stack if everyone should assume that the stack might be trashed and therefore invalid?

In order to be consistent it with your line of reasoning it should simply HLT, then a SIGSEGV handler should set up a preallocated stack, obtain the information and send it off to a logging service using pure system calls before terminating (or send it to the parent process).