digitalmars.D.learn - DbC vs. argument checking
- Niko Korhonen (52/52) May 30 2005 I would like to know what are peoples' strategies with argument
- Jarrett Billingsley (20/30) May 30 2005 I suppose the argument for that is that if your program runs fine in deb...
- Niko Korhonen (10/19) May 30 2005 And what about the situation where incorrect parameters are passed to
- Jarrett Billingsley (29/48) May 31 2005 I'm not saying I agree with that argument; I'm just saying that that's t...
- Derek Parnell (14/18) May 31 2005 And if using the Build utility with the default configuration file, just
-
Jarrett Billingsley
(3/9)
May 31 2005
I believe you forgot the
tags ;) - Derek Parnell (17/29) May 31 2005 What?! I'm perfect now, eh? ;-)
- derick_eddington nospam.yashmoo.com (5/57) May 30 2005 My thoughts are that you should use -release-toggled features to check y...
- Ben Hinkle (11/63) May 30 2005 My own usage is to try to use C/Java instead of in blocks for input vali...
- Derek Parnell (20/26) May 30 2005 My view is that validation of arguments needs to be done so that the use...
- Niko Korhonen (8/14) May 30 2005 shielded
- Derek Parnell (11/19) May 30 2005 That's a judgment call, and the user is the best one to adjudicate.
- Niko Korhonen (15/20) May 31 2005 Ok, that sound very professional. You obviously work for a software
- Derek Parnell (9/33) May 31 2005 Another "improvement" might be to allow the developer better control of
- Derek Parnell (9/18) May 31 2005 Yes I do.
- Mike Parker (7/17) May 30 2005 This goes back to the old C dilemma of 'to assert or not to assert'.
- Derek Parnell (20/39) May 30 2005 I'd add 'resource availability checking' too.
- James Dunne (15/15) May 31 2005 Argument checking sounds like the first valid use of value-based functio...
- Jarrett Billingsley (4/21) May 31 2005 That seems pretty verbose for something that would be more succinctly (a...
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
"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
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 30 2005
"Niko Korhonen" <niktheblak hotmail.com> wrote in message news:d7gvq6$skc$1 digitaldaemon.com...Jarrett Billingsley wrote:I'm not saying I agree with that argument; I'm just saying that that's the reasoning behind it. If you really really need argument checking on something - make it a test in the actual function. And if someone's hacking your program, there's nothing stopping them from skipping the argument validation code ;)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!It's not really a heavy feature. If you think about it, you could write an "in" block as void fork() { debug { // same as an in block } // same as a body block } It's just a debug block that puts its statements at the beginning of the function. As such, you only put things in the "in" block that you only want (need?) to test in the debug phase. Besides, any features to help with debugging are gratefully accepted, no matter how heavy-duty they are. The more heavy-duty they are, usually the more gratefully they are accepted ;)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?Well, there isn't much alternative. You could distibute the source to your library that has debug statements / DbC in it, but then you'd be distributing the source. Besides - switching between debug and release versions of the library would require one small change in the command line. And better yet, if you're using an IDE, that's all handled for you with Debug and Release build configurations.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
On Tue, 31 May 2005 18:27:17 -0400, Jarrett Billingsley wrote:Besides - switching between debug and release versions of the library would require one small change in the command line. And better yet, if you're using an IDE, that's all handled for you with Debug and Release build configurations.And if using the Build utility with the default configuration file, just add +dbg or +prod to command line.... Debugging edition: build myapp +dbg Release edition: build myapp +prod -- Derek Parnell Melbourne, Australia Download BUILD from ... http://www.dsource.org/projects/build/ v2.08 released 29/May/2005 http://www.prowiki.org/wiki4d/wiki.cgi?FrontPage 1/06/2005 9:25:10 AM
May 31 2005
"Derek Parnell" <derek psych.ward> wrote in message news:pziqig2d5vj7.13gea7jfjcyqn.dlg 40tude.net...And if using the Build utility with the default configuration file, just add +dbg or +prod to command line.... Debugging edition: build myapp +dbg Release edition: build myapp +prodI believe you forgot the <shameless_plug> tags ;)
May 31 2005
On Tue, 31 May 2005 22:27:31 -0400, Jarrett Billingsley wrote:"Derek Parnell" <derek psych.ward> wrote in message news:pziqig2d5vj7.13gea7jfjcyqn.dlg 40tude.net...What?! I'm perfect now, eh? ;-) I just wish I was collecting royalties or something for it. The project started as a simple tool for me to use, and I got 'tricked' into supporting other people's needs too. Oh well, all for the better good (I hope). And it's been very useful to help me learn D programming. -- Derek Parnell Melbourne, Australia ************************************************* <plug category="shameless"> Download BUILD from ... http://www.dsource.org/projects/build/ v2.08 released 29/May/2005 </plug> ************************************************* http://www.prowiki.org/wiki4d/wiki.cgi?FrontPage 1/06/2005 12:43:21 PMAnd if using the Build utility with the default configuration file, just add +dbg or +prod to command line.... Debugging edition: build myapp +dbg Release edition: build myapp +prodI believe you forgot the <shameless_plug> tags ;)
May 31 2005
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.
May 30 2005
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
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 30 2005
Derek Parnell wrote:My view is that validation of arguments needs to be done so that theusersof the application can either be informed of erroneous data or beshieldedfrom 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 30 2005
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
May 30 2005
Derek Parnell wrote: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.Ok, that sound very professional. You obviously work for a software company :) Personally I had in mind that I would put argument validation in contracts and profile the DbC enabled version against the release version. If the difference turned out to be negligible, I would ship the DbC enabled version. And I would still be able to throw in an ultra-fast release build if necessary. The downside with this strategy is that compiling with the release switch should be prevented and the reason for this documented. Also (as I've stated numerous times) I'm not satisfied at all with the level of information contained in AssertErrors. Somehow I would *very much* like to use the built-in DbC in D for all purposes. Wasn't the whole point of in, out and invariant blocks to reduce the clutter of argument/other validation code in the function bodies?
May 31 2005
On Tue, 31 May 2005 11:31:35 +0300, Niko Korhonen wrote:Derek Parnell wrote: > 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. Ok, that sound very professional. You obviously work for a software company :) Personally I had in mind that I would put argument validation in contracts and profile the DbC enabled version against the release version. If the difference turned out to be negligible, I would ship the DbC enabled version. And I would still be able to throw in an ultra-fast release build if necessary. The downside with this strategy is that compiling with the release switch should be prevented and the reason for this documented. Also (as I've stated numerous times) I'm not satisfied at all with the level of information contained in AssertErrors. Somehow I would *very much* like to use the built-in DbC in D for all purposes. Wasn't the whole point of in, out and invariant blocks to reduce the clutter of argument/other validation code in the function bodies?Another "improvement" might be to allow the developer better control of what "-release" switch chops out. Let the current syntax "-release" work as it does now, but also allow qualifications such as "-keep=in,assert" to retain 'in' blocks and 'asserts' even if -release is specified. -- Derek Parnell Melbourne, Australia 31/05/2005 9:22:46 PM
May 31 2005
On Tue, 31 May 2005 11:31:35 +0300, Niko Korhonen wrote:Derek Parnell wrote: > 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. Ok, that sound very professional. You obviously work for a software company :)Yes I do. -- Derek Parnell Technical Product Manager - RBX, PBX Admerex Solutions Pty Ltd http://www.admerex.com Melbourne, AUSTRALIA 31/05/2005 9:26:31 PM
May 31 2005
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 30 2005
On Tue, 31 May 2005 10:37:08 +0900, Mike Parker wrote:Niko Korhonen wrote: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 PMHow *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 30 2005
Argument checking sounds like the first valid use of value-based function overloading (read on the digitalmars.D NG) I've heard yet. Default implementation of the function would simply throw argument exceptions, while more specific implementations on values and ranges would allow the data to be passed through. Example: // base function int test(int a, int b is 0 .. 5) { throw new ArgumentException("a is out of range"); } // a and b are in correct ranges int test(int a is 5 .. 10, b is 0 .. 5) { return a + b; } Regards, James Dunne
May 31 2005
"James Dunne" <james.jdunne gmail.com> wrote in message news:d7i23j$23h9$1 digitaldaemon.com...Argument checking sounds like the first valid use of value-based function overloading (read on the digitalmars.D NG) I've heard yet. Default implementation of the function would simply throw argument exceptions, while more specific implementations on values and ranges would allow the data to be passed through. Example: // base function int test(int a, int b is 0 .. 5) { throw new ArgumentException("a is out of range"); } // a and b are in correct ranges int test(int a is 5 .. 10, b is 0 .. 5) { return a + b; } Regards, James DunneThat seems pretty verbose for something that would be more succinctly (and readably) be written as a regular param check.
May 31 2005