Against enforce()

Steven Schveighoffer schveiguy at yahoo.com
Fri Mar 18 09:07:20 PDT 2011


On Fri, 18 Mar 2011 11:35:22 -0400, spir <denis.spir at gmail.com> wrote:

> On 03/18/2011 01:37 PM, Steven Schveighoffer wrote:
>> This is a good example of why it's difficult to decide what "user  
>> input" is.
>> One could consider that the 'user' in this case is the developer using  
>> the
>> library, but I don't think that's the right choice.
>>
>> I'd say it's a bug, this is clearly a contract, since the data being  
>> passed
>> into the ctor can easily not be user input (i.e. it's most likely two  
>> literals
>> that will never depend on a user).  If it is user input, the caller of  
>> the ctor
>> should enforce the user input before passing it to iota.
>
> This is indeed a difficult topic. I'm a bit bluffed when reading people  
> confidently asserting apparently clear positions about the use of  
> enforce vs assert vs contracts and such, or whether such checks should  
> or not stay or not in various distribution builds (mainly -release).
> I can see at least 5 cases, and am far to be sure what the proper tool  
> is in every case, and in which builds it should stay. In each case,  
> there is potential "wrong" input; but note the variety of cases does  
> seems orthogonal (lol) to what kind of harm it may cause:
>
> * colleague: my code is called by code from the same app (same dev  
> team); typically, wrong input logically "cannot" happen
> * friend: my code is called by code designed to cooperate with it; there  
> is a kind of moral contract
> In both cases, wrong input reveals a bug; but in the first case, it's my  
> own (team's) bug. I guess, but am not sure, these cases are good  
> candidates for asserts (or contracts?), excluded from release build.
>
> * lib call: my code is a typical lib; thus, I have zero control on  
> caller.
> I would let the check in release mode, thus use enforce. Or, use assert  
> if it remains when the *caller* is compiled in debug mode. There is  
> something unclear here, I guess. Maybe there are two sub-cases:
> 	~ the caller logically should be able to prove its args correct
> 	~ or not

See, this is where I feel we have issues.  The clear problem with *always*  
checking is the iota example.  One may use iota like this:

foreach(i; iota(0, 5))

Why should checks in iota remain for iota to prove that 0 is less than 5?   
It always will be less than 5, and the check is not necessary.

checks should only be in place during release when the input to the  
function cannot be proven at compile time.  When it can be proven, then  
the checks should go away.

The problem I see is it's iota's responsibility to do those checks, but it  
has no idea where the data comes from.

What I would suggest is to check at the point the argument data is  
created, not at the point where it's used.  So for instance, if you get  
the parameters for iota from an input file, then you need to check those  
arguments before passing to iota.

This is a difficult problem to solve, because one party knows whether the  
arguments need to be checked, and the other party knows how to check the  
arguments.  I don't know if there is a clean way to do this.

My thoughts are that phobos should only use enforce where it can prove the  
arguments are runtime-generated, and rely on asserts otherwise.  The  
obvious pitfall is that one could pass runtime-generated data to a phobos  
function which uses asserts, and the program could crash on an otherwise  
recoverable error because the user of phobos did not validate the input  
first.  I think the risk here is less important than the reduction in  
performance that occurs when enforce is used instead.

> By the way, I don't understand the diff between enforce and  
> alwaysAssert; I thought enforce was precisely an alwaysAssert.

Assert throws an unrecoverable error, and its indication is that there is  
a problem in the code.  An enforce throws a recoverable exception, and  
indicates there is a problem in the runtime input.

-Steve


More information about the Digitalmars-d mailing list