Thread overview
Confusion over enforce and assert - both are compiled out in release mode
Aug 27, 2017
Andrew Chapman
Aug 27, 2017
ag0aep6g
Aug 27, 2017
Andrew Chapman
Aug 27, 2017
Dukc
Aug 27, 2017
Moritz Maxeiner
Aug 27, 2017
Andrew Chapman
Aug 27, 2017
Moritz Maxeiner
Aug 27, 2017
Moritz Maxeiner
August 27, 2017
In the docs regarding contract programming and the use of enforce / assert:
https://dlang.org/library/std/exception/enforce.html

it says:

"enforce is used to throw exceptions and is therefore intended to aid in error handling. It is not intended for verifying the logic of your program. That is what assert is for. Also, do not use enforce inside of contracts (i.e. inside of in and out blocks and invariants), because they will be compiled out when compiling with -release. Use assert in contracts."

However, I am finding that BOTH enforce and assert are compiled out by dmd and ldc in release mode.  Is there a standard way of doing what enforce does inside an "in" contract block that will work in release mode?

I'm guessing I should write my own function for now.
August 27, 2017
On 08/27/2017 12:02 PM, Andrew Chapman wrote:
> However, I am finding that BOTH enforce and assert are compiled out by dmd and ldc in release mode.  Is there a standard way of doing what enforce does inside an "in" contract block that will work in release mode?
> 
> I'm guessing I should write my own function for now.
The whole `in` block is ignored in release mode. Doesn't matter what you put in there. Nothing of it will be compiled.
August 27, 2017
On Sunday, 27 August 2017 at 10:08:15 UTC, ag0aep6g wrote:
> On 08/27/2017 12:02 PM, Andrew Chapman wrote:
>> However, I am finding that BOTH enforce and assert are compiled out by dmd and ldc in release mode.  Is there a standard way of doing what enforce does inside an "in" contract block that will work in release mode?
>> 
>> I'm guessing I should write my own function for now.
> The whole `in` block is ignored in release mode. Doesn't matter what you put in there. Nothing of it will be compiled.

Thanks, that explains it.  I think it's a bit of a shame that the "in" blocks can't be used in release mode as the clarity they provide for precondition logic is wonderful.
August 27, 2017
On Sunday, 27 August 2017 at 10:17:47 UTC, Andrew Chapman wrote:
> On Sunday, 27 August 2017 at 10:08:15 UTC, ag0aep6g wrote:
>> On 08/27/2017 12:02 PM, Andrew Chapman wrote:
>>> However, I am finding that BOTH enforce and assert are compiled out by dmd and ldc in release mode.  Is there a standard way of doing what enforce does inside an "in" contract block that will work in release mode?
>>> 
>>> I'm guessing I should write my own function for now.
>> The whole `in` block is ignored in release mode. Doesn't matter what you put in there. Nothing of it will be compiled.
>
> Thanks, that explains it.  I think it's a bit of a shame that the "in" blocks can't be used in release mode as the clarity they provide for precondition logic is wonderful.

I actually think even better would be if they acted like array bounds checking -always there by default, in release mode done is @safe code but not in @system. And for none if bounds checking is disabled. That would let users implement custom bounds checking types. Asserts would still be always if in release version, bounds checking would be done by if ... throw.
August 27, 2017
On Sunday, 27 August 2017 at 10:17:47 UTC, Andrew Chapman wrote:
> On Sunday, 27 August 2017 at 10:08:15 UTC, ag0aep6g wrote:
>> On 08/27/2017 12:02 PM, Andrew Chapman wrote:
>>> However, I am finding that BOTH enforce and assert are compiled out by dmd and ldc in release mode.  Is there a standard way of doing what enforce does inside an "in" contract block that will work in release mode?
>>> 
>>> I'm guessing I should write my own function for now.
>> The whole `in` block is ignored in release mode. Doesn't matter what you put in there. Nothing of it will be compiled.
>
> Thanks, that explains it.  I think it's a bit of a shame that the "in" blocks can't be used in release mode as the clarity they provide for precondition logic is wonderful.

If you need that, you could compile using ldc in release mode (which you probably want to do anyway):

--- test.d ---
import std.exception;
import std.stdio;

void foo(int x) in { enforce(x > 0); } body
{

}

void bar(int x) in { assert(x > 0); } body
{

}

void baz(int x) in { if (!(x > 0)) assert(0); } body
{

}

void main()
{
    (-1).foo.assertThrown;
    (-1).bar;
    (-1).baz;
}
--------------

$ ldc2 test.d
-> failed assert in bar's in contract terminates the program

$ ldc2 -release test.d
-> failed assertThrown in main terminates the program

$ ldc2 -release -enable-contracts test.d
-> failed assert in baz's in contract terminates the program

$ ldc2 -release -enable-contracts -enable-asserts test.d
-> failed assert in bar's in contract terminates the program
August 27, 2017
On Sunday, 27 August 2017 at 10:37:50 UTC, Moritz Maxeiner wrote:
> On Sunday, 27 August 2017 at 10:17:47 UTC, Andrew Chapman wrote:
>> On Sunday, 27 August 2017 at 10:08:15 UTC, ag0aep6g wrote:
>>> [...]
>>
>> Thanks, that explains it.  I think it's a bit of a shame that the "in" blocks can't be used in release mode as the clarity they provide for precondition logic is wonderful.
>
> If you need that, you could compile using ldc in release mode (which you probably want to do anyway):
>
> --- test.d ---
> import std.exception;
> import std.stdio;
>
> void foo(int x) in { enforce(x > 0); } body
> {
>
> }
>
> void bar(int x) in { assert(x > 0); } body
> {
>
> }
>
> void baz(int x) in { if (!(x > 0)) assert(0); } body
> {
>
> }
>
> void main()
> {
>     (-1).foo.assertThrown;
>     (-1).bar;
>     (-1).baz;
> }
> --------------
>
> $ ldc2 test.d
> -> failed assert in bar's in contract terminates the program
>
> $ ldc2 -release test.d
> -> failed assertThrown in main terminates the program
>
> $ ldc2 -release -enable-contracts test.d
> -> failed assert in baz's in contract terminates the program
>
> $ ldc2 -release -enable-contracts -enable-asserts test.d
> -> failed assert in bar's in contract terminates the program

Oh interesting.  Does DUB support passing through the --enable-contracts flag to ldc?  Also, if this is an ldc specific thing it's probably not a good idea i'd imagine, since in the future one may want to use a GDC, or DMD?
August 27, 2017
On Sunday, 27 August 2017 at 10:46:53 UTC, Andrew Chapman wrote:
> On Sunday, 27 August 2017 at 10:37:50 UTC, Moritz Maxeiner wrote:
>> [...]
>
> Oh interesting.  Does DUB support passing through the --enable-contracts flag to ldc?

Sure, using platform specific build settings [1] such as `"dflags-ldc": ["--enable-contracts"]`.

> Also, if this is an ldc specific thing it's probably not a good idea i'd imagine, since in the future one may want to use a GDC, or DMD?

If you want to use another compiler that supports it, add the appropriate "dflags-COMPILER" setting to your package file.
With regards to dmd: Don't use it for release builds, use gdc or ldc (better optimizations).

https://code.dlang.org/package-format?lang=json#build-settings
August 27, 2017
On Sunday, 27 August 2017 at 10:46:53 UTC, Andrew Chapman wrote:
> [...]
>
> Oh interesting.  Does DUB support passing through the --enable-contracts flag to ldc?  Also, if this is an ldc specific thing it's probably not a good idea i'd imagine, since in the future one may want to use a GDC, or DMD?

Also, with regards to gdc, its release mode `-frelease` option is explicitly specified in the manual as being shorthand for a specific set of options:

>> This is equivalent to compiling with the following options:
>>
>> gdc -fno-assert -fbounds-check=safe -fno-invariants \
>>     -fno-postconditions -fno-preconditions -fno-switch-errors

As it doesn't seem to turn on/off any other options / optimizations, you can use `"dflags-gdc": [...]` to specify your own set of "release" options without losing anything.
In particular, I would overwrite dub's default "release" build type [1] and add your own per compiler build settings, so dub won't pass `-frelease` to gdc when using `dub --build=release`.

[1] https://code.dlang.org/package-format?lang=json#build-types