View mode: basic / threaded / horizontal-split · Log in · Help
May 30, 2005
DbC vs. argument checking
I would like to know what are peoples' strategies with argument 
validation in D. D offers (at least) two solutions for it, first via DbC:

<code>

void f(int x)
  in { assert (x >= 0); }
  body { /* ... */}

</code>

then the C/Java-style if statement:

<code>

void f(int x)
{
  if (x < 0)
    throw new ArgumentOutOfRangeException("x");

  // ...
}

</code>

Current problems with the DbC method are that a generic AssertError 
instead of the proper InException is thrown when the contract is broken. 
 This AssertError gives absolutely no information about what went 
wrong, so for the user of the API/library it's useless.

The other problem is that contracts disappear when compiling with the 
-release switch. The intent of the -release switch is good (to improve 
performance) but for a program whose argument validation is based on 
contracts, it's a disaster. This brings me to the point: argument 
validation scenarios. The current alternatives for argument validation 
in D roughly are:

1) Use only C/Java-style argument validation
2) Use contracts for argument validation and forbid compilation in 
release mode
3) Use a mix of these styles

The first scenario is possible, but sad because then a wonderful 
language feature would go unused.

The second scenario would be nice, but it's a bit hackish; shouldnt a 
proper program compile and work well also in release mode? And then 
there's the performance issue; what if some of the contracts do heavy 
debugging work (for example traverse an array) and they /should/ be 
disabled in the release build? We can't selectively drop some contracts 
and keep others. So this isn't a perfect solution.

Scenario three is the most difficult since how do we know when to use 
C/Java-style validation and when contracts? I also think this kind of 
mixing is ugly.

Delivering an API/library that doesn't validate arguments at all is not 
an option, not in this buffer overrun viral world of current computing.

How *should* D libraries be designed? Totally trust the user, no 
argument validation at all? Use contracts, no argument validation in 
release mode? Always use C/Java-style argument validation in public 
API's, contracts with private? Always use C/Java-style argument 
validation, period?

IMO DbC adds complexity to the D language because both DbC and 
C/Java-style argument validation schemes are possible, and there doesn't 
seem to be any real guidelines on when to use which. I would really 
appreciate your input on this issue.
May 30, 2005
Re: DbC vs. argument checking
"Niko Korhonen" <niktheblak@hotmail.com> wrote in message 
news:d7f5it$24uo$1@digitaldaemon.com...
> The other problem is that contracts disappear when compiling with 
> the -release switch. The intent of the -release switch is good (to improve 
> performance) but for a program whose argument validation is based on 
> contracts, it's a disaster.

I suppose the argument for that is that if your program runs fine in debug, 
and contracts are always met, then it'll run fine in release mode.  The 
contracts are really only there for the dev phase, where you might 
accidentally give functions incorrect params.

> The first scenario is possible, but sad because then a wonderful language 
> feature would go unused.

Again, I think the contracts are really only meant to be used in the 
debugging phase.  You can use them, but only when you're in the process of 
writing your program.

> How *should* D libraries be designed? Totally trust the user, no argument 
> validation at all? Use contracts, no argument validation in release mode? 
> Always use C/Java-style argument validation in public API's, contracts 
> with private? Always use C/Java-style argument validation, period?

Personally I use C style validation, but I optionally throw a "debug" in 
front of it, a la

debug if(x<10)
   throw new Exception("x was less than 10!");

This particular argument check is only compiled in debug mode, and is 
skipped in the release build.  If I need something to be in the release 
build as well, I simply leave off the "debug".

Additionally, you asked how to deliver a good API.  Well, many libraries 
I've seen come with two versions - debug and release.  That way, the debug 
version of the API has all the contracts and parameter validation, while the 
release code has all (or most) of that removed for speed.
May 30, 2005
Re: DbC vs. argument checking
In article <d7f5it$24uo$1@digitaldaemon.com>, Niko Korhonen says...
>
>I would like to know what are peoples' strategies with argument 
>validation in D. D offers (at least) two solutions for it, first via DbC:
>
><code>
>
>void f(int x)
>   in { assert (x >= 0); }
>   body { /* ... */}
>
></code>
>
>then the C/Java-style if statement:
>
><code>
>
>void f(int x)
>{
>   if (x < 0)
>     throw new ArgumentOutOfRangeException("x");
>
>   // ...
>}
>
></code>
>
>Current problems with the DbC method are that a generic AssertError 
>instead of the proper InException is thrown when the contract is broken. 
>  This AssertError gives absolutely no information about what went 
>wrong, so for the user of the API/library it's useless.
>
>The other problem is that contracts disappear when compiling with the 
>-release switch. The intent of the -release switch is good (to improve 
>performance) but for a program whose argument validation is based on 
>contracts, it's a disaster. This brings me to the point: argument 
>validation scenarios. The current alternatives for argument validation 
>in D roughly are:
>
>1) Use only C/Java-style argument validation
>2) Use contracts for argument validation and forbid compilation in 
>release mode
>3) Use a mix of these styles
>
>The first scenario is possible, but sad because then a wonderful 
>language feature would go unused.
>
>The second scenario would be nice, but it's a bit hackish; shouldnt a 
>proper program compile and work well also in release mode? And then 
>there's the performance issue; what if some of the contracts do heavy 
>debugging work (for example traverse an array) and they /should/ be 
>disabled in the release build? We can't selectively drop some contracts 
>and keep others. So this isn't a perfect solution.
>
>Scenario three is the most difficult since how do we know when to use 
>C/Java-style validation and when contracts? I also think this kind of 
>mixing is ugly.
>
>Delivering an API/library that doesn't validate arguments at all is not 
>an option, not in this buffer overrun viral world of current computing.
>
>How *should* D libraries be designed? Totally trust the user, no 
>argument validation at all? Use contracts, no argument validation in 
>release mode? Always use C/Java-style argument validation in public 
>API's, contracts with private? Always use C/Java-style argument 
>validation, period?
>
>IMO DbC adds complexity to the D language because both DbC and 
>C/Java-style argument validation schemes are possible, and there doesn't 
>seem to be any real guidelines on when to use which. I would really 
>appreciate your input on this issue.

My thoughts are that you should use -release-toggled features to check your own
logic/assumptions about things entirely under your control and use always-there
checks on anything clients (both clients of a library or an app) can influence.
So, #3.
May 30, 2005
Re: DbC vs. argument checking
In article <d7f5it$24uo$1@digitaldaemon.com>, Niko Korhonen says...
>
>I would like to know what are peoples' strategies with argument 
>validation in D. D offers (at least) two solutions for it, first via DbC:
>
><code>
>
>void f(int x)
>   in { assert (x >= 0); }
>   body { /* ... */}
>
></code>
>
>then the C/Java-style if statement:
>
><code>
>
>void f(int x)
>{
>   if (x < 0)
>     throw new ArgumentOutOfRangeException("x");
>
>   // ...
>}
>
></code>
>
>Current problems with the DbC method are that a generic AssertError 
>instead of the proper InException is thrown when the contract is broken. 
>  This AssertError gives absolutely no information about what went 
>wrong, so for the user of the API/library it's useless.
>
>The other problem is that contracts disappear when compiling with the 
>-release switch. The intent of the -release switch is good (to improve 
>performance) but for a program whose argument validation is based on 
>contracts, it's a disaster. This brings me to the point: argument 
>validation scenarios. The current alternatives for argument validation 
>in D roughly are:
>
>1) Use only C/Java-style argument validation
>2) Use contracts for argument validation and forbid compilation in 
>release mode
>3) Use a mix of these styles
>
>The first scenario is possible, but sad because then a wonderful 
>language feature would go unused.
>
>The second scenario would be nice, but it's a bit hackish; shouldnt a 
>proper program compile and work well also in release mode? And then 
>there's the performance issue; what if some of the contracts do heavy 
>debugging work (for example traverse an array) and they /should/ be 
>disabled in the release build? We can't selectively drop some contracts 
>and keep others. So this isn't a perfect solution.
>
>Scenario three is the most difficult since how do we know when to use 
>C/Java-style validation and when contracts? I also think this kind of 
>mixing is ugly.
>
>Delivering an API/library that doesn't validate arguments at all is not 
>an option, not in this buffer overrun viral world of current computing.
>
>How *should* D libraries be designed? Totally trust the user, no 
>argument validation at all? Use contracts, no argument validation in 
>release mode? Always use C/Java-style argument validation in public 
>API's, contracts with private? Always use C/Java-style argument 
>validation, period?
>
>IMO DbC adds complexity to the D language because both DbC and 
>C/Java-style argument validation schemes are possible, and there doesn't 
>seem to be any real guidelines on when to use which. I would really 
>appreciate your input on this issue.

My own usage is to try to use C/Java instead of in blocks for input validation
and out blocks and invariants to validate program logic. I would love it if in
blocks were treated differently than out/invariant blocks since they serve
different purposes. I think there have been several threads about this sort of
thing - what kinds of compiler options should turn on or off the different DbC
constructs. If phobos had been built with in blocks enabled a large set of bugs
in std.stream would have been squashed long ago. It would also be nice to have
some standard input checking exceptions available for throwing but that hasn't
been done together with other exception refactoring in phobos. I'm doubtful any
guidelines or changes will come down the pipe before 1.0, though.
May 30, 2005
Re: DbC vs. argument checking
On Mon, 30 May 2005 16:48:13 +0300, Niko Korhonen wrote:

> I would like to know what are peoples' strategies with argument 
> validation in D.

[snip]

> IMO DbC adds complexity to the D language because both DbC and 
> C/Java-style argument validation schemes are possible, and there doesn't 
> seem to be any real guidelines on when to use which. I would really 
> appreciate your input on this issue.

My view is that validation of arguments needs to be done so that the users
of the application can either be informed of erroneous data or be shielded
from it. And by 'users', I include both people and calling routines. Thus,
the 'in' block is not the best place to validate the input arguments for
any routine that is going to be compiled under the '-release' switch.

Using the assert() function to inform end users of bad data is also a poor
strategy, since such checks are removed by '-release'. Either use
exceptions or traditional error processing. Use the assert() function to
validate processes rather than data, as these need to be proved before a
Release edition of the application is available to the end user.

The 'out' block is still useful because its purpose is to detect logic
errors, as opposed to data errors, that the developer has coded into the
routine. These logic errors need to be tested and detected prior to the
routine being compiled with '-release'.


-- 
Derek
Melbourne, Australia
31/05/2005 9:09:14 AM
May 31, 2005
Re: DbC vs. argument checking
Niko Korhonen wrote:

> How *should* D libraries be designed? Totally trust the user, no 
> argument validation at all? Use contracts, no argument validation in 
> release mode? Always use C/Java-style argument validation in public 
> API's, contracts with private? Always use C/Java-style argument 
> validation, period?
> 
> IMO DbC adds complexity to the D language because both DbC and 
> C/Java-style argument validation schemes are possible, and there doesn't 
> seem to be any real guidelines on when to use which. I would really 
> appreciate your input on this issue.

This goes back to the old C dilemma of 'to assert or not to assert'. 
And, IMO, the answer is the same. If you know the input can be generated 
at runtime by the user (a configuration file, a script, typed in from 
the keyboard, etc...) then you should be validating it with an if 
statement. Otherwise, use the DBC constructs so that you don't pay the 
price of validation when it isn't needed.
May 31, 2005
Re: DbC vs. argument checking
On Tue, 31 May 2005 10:37:08 +0900, Mike Parker wrote:

> Niko Korhonen wrote:
> 
>> How *should* D libraries be designed? Totally trust the user, no 
>> argument validation at all? Use contracts, no argument validation in 
>> release mode? Always use C/Java-style argument validation in public 
>> API's, contracts with private? Always use C/Java-style argument 
>> validation, period?
>> 
>> IMO DbC adds complexity to the D language because both DbC and 
>> C/Java-style argument validation schemes are possible, and there doesn't 
>> seem to be any real guidelines on when to use which. I would really 
>> appreciate your input on this issue.
> 
> This goes back to the old C dilemma of 'to assert or not to assert'. 
> And, IMO, the answer is the same. If you know the input can be generated 
> at runtime by the user (a configuration file, a script, typed in from 
> the keyboard, etc...) then you should be validating it with an if 
> statement. Otherwise, use the DBC constructs so that you don't pay the 
> price of validation when it isn't needed.

I'd add 'resource availability checking' too.

 void func()
 {
    assert( exists("C:\\special.file") == true) ;
    . . .
 }

This example would be useless in production code. The resource's
availability is only checked during development.

 void func()
 {
    if( exists("C:\\special.file") == false)
       throw new Exception( ... );
    . . .
 }

This at least let's the user know about the problem.

-- 
Derek
Melbourne, Australia
31/05/2005 12:06:53 PM
May 31, 2005
Re: DbC vs. argument checking
Jarrett Billingsley wrote:
> I suppose the argument for that is that if your program runs fine in debug, 
> and contracts are always met, then it'll run fine in release mode.

And what about the situation where incorrect parameters are passed to 
the release mode program, either by accident or by purposeful hacking?

I just /can't/ throw away the life jacket of vigorous argument checking 
when delivering a program/library, no matter how well it ran in test 
environment!

> Again, I think the contracts are really only meant to be used in the 
> debugging phase.  You can use them, but only when you're in the process of 
> writing your program.

Isn't it a rather heavy feature just for dev phase debugging?

> Additionally, you asked how to deliver a good API.  Well, many libraries 
> I've seen come with two versions - debug and release.  That way, the debug 
> version of the API has all the contracts and parameter validation, while the 
> release code has all (or most) of that removed for speed. 

That might work and might also be practical. But somehow I just don't 
like it. Besides, in some situations switching a library on the fly when 
trying to hunt down a mysterious problem might not be practical at all.
May 31, 2005
Re: DbC vs. argument checking
Derek Parnell wrote:
> My view is that validation of arguments needs to be done so that the 
users
> of the application can either be informed of erroneous data or be 
shielded
> from it. And by 'users', I include both people and calling routines.

Ok, it seems reasonable. But even when it costs performance?

> Thus,
> the 'in' block is not the best place to validate the input arguments for
> any routine that is going to be compiled under the '-release' switch.

Definitely not. Not only does the validation disappear when building in 
release mode, the information the user is able to obtain from the 
AssertErrors is extremely limited. Without access and willingness to 
browse the source code it's zero.
May 31, 2005
Re: DbC vs. argument checking
On Tue, 31 May 2005 09:29:03 +0300, Niko Korhonen wrote:

> Derek Parnell wrote:
>  > My view is that validation of arguments needs to be done so that the 
> users
>  > of the application can either be informed of erroneous data or be 
> shielded
>  > from it. And by 'users', I include both people and calling routines.
> 
> Ok, it seems reasonable. But even when it costs performance?

That's a judgment call, and the user is the best one to adjudicate. 

I tend to place the validation code in the release edition that is to
undergo User Acceptance testing. If, and only if, the user objects to the
performance, I explain the ramifications of removing it and then let the
user decide. The corresponding User Requirements specification is updated
accordingly.

-- 
Derek
Melbourne, Australia
31/05/2005 4:40:25 PM
« First   ‹ Prev
1 2
Top | Discussion index | About this forum | D home