March 04, 2018
On Sunday, 4 March 2018 at 00:32:20 UTC, Walter Bright wrote:
> On 4/12/2017 4:25 AM, Mike Parker wrote:
>> DIP 1006 is titled "Providing more selective control over contracts".
>> 
>> https://github.com/dlang/DIPs/blob/master/DIPs/DIP1006.md
>
>
> Currently, we have 3 switches that affect the asserts: `release`, `boundscheck`, and `unittest`. The documentation for these new additions is completely confusing. No mention is made of interactions with the latter two. No mention is made on what happens if more than one of these switches is used, or what if the same switch appears multiple times.
>
> I'd like to see a chart enumerating all the behaviors influenced by these switches, the default behavior, and which switch settings do what.
>
> Each switch, when applied, should specify what happens to each behavior:
>
> 1. turned on
> 2. turned off
> 3. not affected
>
> and that the switches are applied in the order they appear on the command line.
>
> The use of comma-separated arguments is something I've argued against for other switches. The use of `-release=in -release=out` should be fine and is less confusing/buggy to implement.
>

Why?  Implementation is trivial (unit testable no less!) , see https://github.com/dlang/dmd/pull/7863 and extensible to other args.

> The idea that `-release=in` actually turns *off* `in` is completely topsy-turvy.
>
> Ideally, the whole thing should be simplified to its fundamentals:
>
> 1. leave the old switches as they are
> 2. Add a new switch, let's say "check":
>
>    -check     turn on all checks
>    -check=on  turn on all checks
>    -check=off turn off all checks
>    -check=xxx turn on check xxx
>    -check=yyy turn on check yyy
>
> simple, easy to explain, easy to comprehend, easy to implement, easy to extend with new checks.

I think aggregation is a good idea. So is phrasing in the positive sense, except for it looks like xxx and yyy are _off_ by default, where surely we want all checks _on_ by default.

March 03, 2018
On 3/3/2018 5:29 PM, Nicholas Wilson wrote:
>> The use of comma-separated arguments is something I've argued against for other switches. The use of `-release=in -release=out` should be fine and is less confusing/buggy to implement.
> Why?  Implementation is trivial (unit testable no less!) , see https://github.com/dlang/dmd/pull/7863 and extensible to other args.

It's not trivial. First, it's 100 lines of code (with no comments) just for that, and there are templates and behaviors with memory allocation. Moving along that path, we're gradually reinventing std.getopt which is 1814 lines (with comments).

Generally, people will be driving dmd with a makefile, dmd.conf, or other response file. It's complicated enough already, and gets constantly worse. Once in, we're stuck with it forever. I just don't feel it is worthwhile spending time on this.


> I think aggregation is a good idea. So is phrasing in the positive sense, except for it looks like xxx and yyy are _off_ by default, where surely we want all checks _on_ by default.

The default is that they're all on. So to just have one on, first turn them all off then turn on the desired ones.

March 04, 2018
On Sunday, 4 March 2018 at 04:30:31 UTC, Walter Bright wrote:
> It's not trivial. First, it's 100 lines of code (with no comments) just for that, and there are templates and behaviors with memory allocation. Moving along that path, we're gradually reinventing std.getopt which is 1814 lines (with comments).

I disagree, it is 100 (slightly less) lines of modular code and can be used for -i,-I,-J,-check and possibly a whole lot more.
Yes there are no comments but it's not exactly difficult to follow.
You get that from modular code.

parseCommandLine is 746! and is much more complicated.
I'm very glad that in LDC we have access to LLVM command line arguments
which are purely declarative.

> Generally, people will be driving dmd with a makefile, dmd.conf, or other response file.

You still have to write those.

>It's complicated enough already, and gets constantly worse.

And it won't get simpler unless anything is done about it!

> Once in, we're stuck with it forever.

We can (and do) deprecate things.

> I just don't feel it is worthwhile spending time on this.

Then the situation will not improve. It is a shame to lose this excellent work.

>> I think aggregation is a good idea. So is phrasing in the positive sense, except for it looks like xxx and yyy are _off_ by default, where surely we want all checks _on_ by default.
>
> The default is that they're all on.

Good.

> So to just have one on, first turn them all off then turn on the desired ones.

Not so good. That is the opposite pattern of use I would expect. I would much rather turn them off individually, because I might forget one or a new release might add more and then it is off by default. Not to mention it result in way more args and the intention is much less clear .
Looking at a command line invocation of DMD could you figure out which checks are off by looking at:
` -checks=off -checks=boundscheck -checks=in -checks=out -checks=unittest`
don't forget they could be interspersed between other args _and_ be in the conf file. The types of checks are a closed set, it makes sense to specify them all at once.
March 04, 2018
On Sat, 03 Mar 2018 20:30:31 -0800, Walter Bright wrote:

> The default is that they're all on. So to just have one on, first turn them all off then turn on the desired ones.

Would I be correct to interpret this as "turn them all off with -release"?

E.g., "dmd -check=in a.d" is unnecessary; it's equivalent to "dmd a.d" "dmd -release -check=in a.d" turns off all checks except in contracts.

If adding any check turns everything else off, that seems strange; that said, wouldn't -check=off be equivalent to -release? Do we need -check=off and -check=on, since it just duplicates the -release toggle?

I do like adding the -check switch because it reads far more naturally than -release=in, etc. But as far as readability, only using -check once -release is passed to disable everything makes sense, as using -check shouldn't disable other checks, and -release shows intention better than starting with -check=off


--Ryan
March 04, 2018
On 3/4/2018 4:05 AM, rjframe wrote:
> Would I be correct to interpret this as "turn them all off with -release"?

Array bounds checking is left on with -release.
March 04, 2018
On 04.03.2018 21:40, Walter Bright wrote:
> On 3/4/2018 4:05 AM, rjframe wrote:
>> Would I be correct to interpret this as "turn them all off with -release"?
> 
> Array bounds checking is left on with -release.

Not necessarily. If the code contains an explicit assertion that the index is in bounds, then, according to the language specification, the bounds check may be removed with -release.

I find the reasoning in terms of "on"/"off" confusing anyway.
Does "off" mean "contract/assertion removed", or does it mean "failure is UB"?
March 04, 2018
On 3/4/2018 1:16 PM, Timon Gehr wrote:
> On 04.03.2018 21:40, Walter Bright wrote:
>> On 3/4/2018 4:05 AM, rjframe wrote:
>>> Would I be correct to interpret this as "turn them all off with -release"?
>>
>> Array bounds checking is left on with -release.
> 
> Not necessarily. If the code contains an explicit assertion that the index is in bounds, then, according to the language specification, the bounds check may be removed with -release.

D, as all languages that I know of do implicitly or explicitly, generates code based on the "as if" rule.


> I find the reasoning in terms of "on"/"off" confusing anyway.
> Does "off" mean "contract/assertion removed", or does it mean "failure is UB"?

"Off" means the check is removed. If the check does not hold, the program enters an invalid state, whether or not the check was actually done. An invalid state means subsequent execution is UB.
March 05, 2018
On 04.03.2018 22:49, Walter Bright wrote:
> On 3/4/2018 1:16 PM, Timon Gehr wrote:
>> On 04.03.2018 21:40, Walter Bright wrote:
>>> On 3/4/2018 4:05 AM, rjframe wrote:
>>>> Would I be correct to interpret this as "turn them all off with -release"?
>>>
>>> Array bounds checking is left on with -release.
>>
>> Not necessarily. If the code contains an explicit assertion that the index is in bounds, then, according to the language specification, the bounds check may be removed with -release.
> 
> D, as all languages that I know of do implicitly or explicitly, generates code based on the "as if" rule.
> ...

Impossible. You wrote a Java compiler.

All languages that use your "as if" rule are memory unsafe.
Zero languages that use the "as if" rule have any memory safe subset that includes assertions.

In D, assert is @safe, and it should remain @safe.

> 
>> I find the reasoning in terms of "on"/"off" confusing anyway.
>> Does "off" mean "contract/assertion removed", or does it mean "failure is UB"?
> 
> "Off" means the check is removed. If the check does not hold, the program enters an invalid state, whether or not the check was actually done. An invalid state means subsequent execution is UB.

Why is potential memory corruption to be expected when using @safe language features with a flag to disable contract checks? This makes no sense. This is not useful behavior. There are convenient ways to support potentially unsound compilation hints that do not do this. Contracts and compilation hints should be orthogonal. Contracts should be potentially @safe, compilation hints should be @system always.

Note that _actual removal_ is the only use case of 'disabling contracts' that I care about, and I think many D programmers who use "off" will also have this behavior in mind. Yet this is not even an option.

At the very least, the DIP should be up-front about this.
I'm still not even sure that Mathias Lang intended the UB semantics.
March 05, 2018
On Sunday, 4 March 2018 at 12:05:08 UTC, rjframe wrote:
> E.g., "dmd -check=in a.d" is unnecessary; it's equivalent to "dmd a.d" "dmd -release -check=in a.d" turns off all checks except in contracts.

I think, -check should specify hierarchic modes like in the DIP, that would work independently of -release switch (override).
March 05, 2018
On 3/4/2018 3:06 PM, Timon Gehr wrote:
> On 04.03.2018 22:49, Walter Bright wrote:
>>> Not necessarily. If the code contains an explicit assertion that the index is in bounds, then, according to the language specification, the bounds check may be removed with -release.
>>
>> D, as all languages that I know of do implicitly or explicitly, generates code based on the "as if" rule.
>> ...
> 
> Impossible. You wrote a Java compiler.

Even in Java, the compiler generates code that, from the user's point of view, behaves "as if" the code was actually what was specified. For a trivial example, replacing x*2 with x<<1. Not having this means no optimizations can be done.


> All languages that use your "as if" rule are memory unsafe.
> Zero languages that use the "as if" rule have any memory safe subset that includes assertions.
> In D, assert is @safe, and it should remain @safe.

>>> I find the reasoning in terms of "on"/"off" confusing anyway.
>>> Does "off" mean "contract/assertion removed", or does it mean "failure is UB"?
>>
>> "Off" means the check is removed. If the check does not hold, the program enters an invalid state, whether or not the check was actually done. An invalid state means subsequent execution is UB.
> 
> Why is potential memory corruption to be expected when using @safe language features with a flag to disable contract checks?

Because the checks provide extra information to the compiler that it can use to generate better code. If that extra information is not true, then the better code will be invalid.

Memory safety is only one class of errors in a program. If the program has entered a state that is not accounted for by the programmer, the rest of the program's execution will be not predictable.


> This makes no sense. This is not useful behavior. There are convenient ways to support potentially unsound compilation hints that do not do this. Contracts and compilation hints should be orthogonal. Contracts should be potentially @safe, compilation hints should be @system always.
> 
> Note that _actual removal_ is the only use case of 'disabling contracts' that I care about, and I think many D programmers who use "off" will also have this behavior in mind. Yet this is not even an option.

I don't see much use for this behavior, unless you want to continue running the program after an assert failure, which I cannot recommend and the language is not designed to support. But you can always do something like:

   version (ignore_asserts) { } else { assert(...); }

which would optionally remove both the runtime check and any compiler use of the assert. Or you could use https://dlang.org/library/std/exception/enforce.html which has no influence on compiler semantics.


> At the very least, the DIP should be up-front about this.
> I'm still not even sure that Mathias Lang intended the UB semantics.

It being UB was my doing, not Mathias'. DIP1006 is not redefining the semantics of what assert does.