digitalmars.D - Re: Against enforce()

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

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