try/catch idiom in std.datetime

Jonathan M Davis jmdavisProg at gmx.com
Mon Nov 18 15:42:13 PST 2013


On Monday, November 18, 2013 14:40:51 Walter Bright wrote:
> I'm glad we're discussing this. There's an important misunderstanding.
> 
> On 11/18/2013 2:16 PM, Jonathan M Davis wrote:
> > But that would just duplicate the validation. You validate by parsing the
> > string, and you extract the necessary data from it by parsing it.
> > Validating the data first would just double the work - on top of the fact
> > that strings are most likely to have come from outside the program rather
> > than having been generated internally and then parsed internally. This is
> > exactly the sort of case where I think that separate validation makes no
> > sense. Separate validation only makes sense when the result is _less_
> > overhead, not more.
> The point of asserts is that they are supposed to be redundant. (If they
> were not redundant, then they would trip and you'd have a program bug.)
> Asserts are there to detect program bugs, not to validate input data. This
> is also why the optimizer can remove asserts without affecting the meaning
> of the code.

I understand this. The problem is that in some cases, in order to do the 
check, you have to do all of the work that the function you're trying to 
protect bad input from has to do anyway - even without it asserting anything. 
So, having a separate function do the checking would just be extra overhead. 
For instance, if you had to parse a string in order to get data out of it, the 
function checking the string's validity would have parse the string out and 
get all of the data out of it, validating the string's format and the data's 
validity in the process, whereas the function that does the actual parsing to 
give you the result (as opposed to checking the input) has to do all of that 
same parsing and data extraction. Maybe, if another function had already 
validated the string, it could avoid a few of the checks, but many of them 
have to be done just to parse the string (e.g. if its format is wrong, you 
can't even get at the data properly, regardless of whether the data is valid 
or not). So, you don't save much in the way of checking if you have a 
validation function, and you add overhead, because the data has to be 
processed twice.

In other cases, validation is as simple as asserting something about the 
input, in which case, it's simple enough to assert within the function (which 
would then go away in -release) and to have a validation function do the 
checking and get no extra overhead, but that's not always the case, and when 
it's not, it makes no sense to me to use DbC. In such cases, defensive 
programming makes far more sense.

Also, if the data _always_ has to be checked (which isn't always the case in 
std.datetime), then it makes no sense to separate the validation from the 
function doing the work.

I think that whether DbC or defensive programming is more appropriate comes 
down primarily to two things:

1. Does the validation need to be part of the function for it to do its job, 
or does doing the validation require doing what the function is going to do 
anyway? If so, the defensive programming makes more sense. If not, then DbC 
makes more sense.

2. Is this function treating its caller as part of the program or as a user? 
If the caller is being treated as part of the program, then DbC tends to make 
sense, as its reasonable to require that the caller knows what the function 
requires and is effectively part of the same code as the function. If the 
caller is being treated as a user (as is often going to be the case with 
libraries), then it's generally better to use defensive programming, because 
it ensures that the function gets and operates on valid input rather than 
resulting in undefined behavior when the caller gives bad input (and unless the 
library is compiled without -release or the function is templated, assertions 
won't do anything to help in a library).

Efficiency tends toward lean towards using DbC, whereas user-friendliness leans 
toward defensive programming. In general, I would use DbC internally to a 
program and defensive programming in a library.

Having validator functions definitely helps with DbC, as it gives the caller a 
way to validate the input when necessary and avoid the validation when it 
isn't. But it puts all the onus on the caller and makes it much, much more 
likely that functions will be misused, and if the function is in a library, 
then the odds are that if validation is done incorrectly by the caller, it'll 
never get checked by the callee, and you'll end up with buggy code with 
undefined behavior.

I think that you bring up good points, but I also don't think that the 
situation is anywhere near as clearcut as you do.

- Jonathan M Davis


More information about the Digitalmars-d mailing list