against enforce
Jonathan M Davis
jmdavisProg at gmx.com
Fri Mar 25 12:21:26 PDT 2011
> >So, there really is no good answer.
> >- Jonathan M Davis
>
> So why do you need to differentiate between assert and enforce if you can't
> choose, which of them should be used?
>
> We can't really turn off both of them, and if we really want performance
> and no checks, we would want to turn off both of them, so they should work
> in the same way, shouldn't they?
assert and enforce serve _very_ different purposes. assert is for checking the
logic of your code. It can go away, so you can't rely on it. It's simply for
additional checks in your code to ensure that it's of high quality. You can't
rely on it. It's also _not_ for error handling. When an assertion fails, there
is a bug in your program.
Exceptions - and therefore enforce - are for error handling. They are supposed
to _always_ be there. Performance has nothing to do with them (other than the
fact that they can obviously harm performance, which may cause you to refactor
your code so that they're not necessary). Typically, exceptions - and
therefore enforce - are used when validating input. That input is often
completely dependent on the particular run of the program, and bad input isn't
necessarily a bug in the program at all. When enforce fails, that does _not_
necessarily indicate a bug in your program, and it should _not_ be used for
finding bugs.
Input from the user is obviously always input, and you're going to have to
check that and throw an exception on failure rather than use assertions. Input
to a function which is completely local to your code is not in any API
anywhere and whose input is completely controlled by your code should use
assertions. At that point, if the function gets bad input, it's a bug in your
code. Also, out blocks, invariants, and checks in the middle of functions
typically have _nothing_ to do with input and should be assertions. If they
fail it's a logic bug.
The problem is when a function could be both used internally and used on user
input. For instance, iota is typically given hard-coded values - iota(5, 100,
2) - but you could pass it value which was given to main - iota(5, 100,
to!int(args[1]). With hard-coded values, assert is the correct solution. But
with user input, enforce would be. So, which do you do? assert or enforce?
In the case of iota, since it is almost always used with hard-coded values and
even when it isn't, it's likely used with computed values rather than user
input, so if it's wrong, it's a bug in the code rather than bad user input.
The application can check (with enforce or with an if and throwing an
exception or whatever) that the input is good before passing it to iota if
that's what it's doing.
With other functions though, it's less clear. And with every such function, a
choice must be made. Should it treat its input as user input or as values
local to the program? If it's user input, then it needs to use exceptions. If
it's local to the program (at which point a bad value would be a bug in the
program), then assert should be used. And when you're dealing with a library,
it's not as clear what the best solution should be in. The fact that
assertions are almost certainly going to be compiled out might make it so that
you want to treat input to the library's API as user input rather than local
to the program when you would choose to have those same functions be treated
as local to the program if they weren't in another library (though of course,
there are plenty of cases where API functions should just plain be treating
input as user input regardless).
So, there is a clear and distinct difference between the intended uses of
assert and exceptions (and therefore enforce). They have very different roles.
The question then is not what their roles are but what you need a particular
function to do - e.g. treat it's input as user input or treat it as local to
the program (and therefore a bug if it's wrong).
- Jonathan M Davis
More information about the Digitalmars-d
mailing list