www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: Against enforce()

reply Kagamin <spam here.lot> writes:
So how do you solve the problem?

---------
 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.

You can't validate all user input, so external data ends up spead across your entire application. So I don't understand obsession with -release switch, because contracts most of the time do validate user input. If we think about -release switch as a HP-hack for exotic code, there will be no ideological difference between assert and enforce.

As has been point out, the problem is in cases where it's not clear whether you should treat input as user input (and therefore needs to _always_ be checked and have exceptions thrown on error) or whether you should treat input as being from your program and guaranteed to be valid (at which point you use assert to check that that guarantee actually holds). ----------
Mar 24 2011
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
 So how do you solve the problem?
 
 ---------
 
 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.

You can't validate all user input, so external data ends up spead across your entire application. So I don't understand obsession with -release switch, because contracts most of the time do validate user input. If we think about -release switch as a HP-hack for exotic code, there will be no ideological difference between assert and enforce.

As has been point out, the problem is in cases where it's not clear whether you should treat input as user input (and therefore needs to _always_ be checked and have exceptions thrown on error) or whether you should treat input as being from your program and guaranteed to be valid (at which point you use assert to check that that guarantee actually holds). ----------

It's a case by case thing. In some cases, you go with assertions and let the code choke horribly (or worse, silently sort of work but not quite right) if it's used in a case where it should have been an exception. In others, you use exceptions and just let the efficiency be degraded. It depends on the situation and what you're trying to do. In many cases, you'd go with an assertion and make it clear that the caller needs to check if they want the function to actually work correctly. Then it's up to the caller to check or not. There is no good answer for what to _always_ do in this sort of situation, because the costs can vary considerably from situation to situation. If the function is very cheap, then having additional checks in release mode could be devastating, and you just can't afford to be throwing exceptions from it. On the other hand, if it's very expensive, then having the additional checks wouldn't matter at all. The big question is what the general policy should be in Phobos functions. Should the default choice be to use an assertion, which will usually then do no checks at all, because assertions are almost always compiled out in Phobos (unless people compile it themselves), or should enforce be used and then have the additional cost in there all of the time. I would guess that iota is most frequently used with known values at compile time - iota(1, 512) - in which case assert makes perfect sense. In others, the value used could be based on lots of calculations somewhere and maybe even depends on user input - iota(a, b). The best choice would depend on what we expect the typical use case to be and how high the cost is to pick the other choice. The other possibility is to specifically have two versions of a function: one which uses an assertion (which may or may not be enabled) and therefore essentially does no checking, thereby requiring that the programmer ensure that the arguments are correct or the function could do funny things, and one which uses an exception. Then the programmer could choose whether they want the checks to occur or not (e.g. iota could assert or do no checks at all and iotoE could throw an exception). However, that doesn't scale very well if you try and do that with every function that has this problem. So, there really is no good answer. - Jonathan M Davis
Mar 24 2011