About a week ago I got enthused to work on another coding project I've been
wanting to experiment with for a long time. I discovered that it was highly
addictive and I just couldn't put it down. It's also given me some interesting
ideas for a higher level interface to bsdnt. But more on that later when we
start working on it.
Unfortunately in that week of time there have been no bsdnt updates.
Moreover, on the weekend my main computer died (physical hard drive failure).
I pulled out my backup machine and Windows wanted to install 3 months of
"important updates". Naturally this caused the machine to crash, I was unable
to recover to the restore point it set, the startup repair didn't work and
the only solution was a format and reload.
*Fifteen and a half hours* later I had reinstalled Windows and it had finally
finished putting the approximately 165 "important updates" back on!!
Unfortunately all the bsdnt blog articles I had meticulously prepared in
advance were lost. Thus I am regenerating what I can from the diff between
revisions of bsdnt. Sorry if they end up being shorter than past updates.
Fortunately I did not lose any of the code I wrote, as that was backed up in
a git repo on an external server!
Anyhow, in this update we make a very simple change to bsdnt, again in an
attempt to improve the test quality of the library. We add asserts to the
code.
An assert is a check that is made at runtime in live code to test if some
predefined condition holds. If the assert fails, an error message is printed
specifying the line of code where the assert is located and what the
condition was that failed.
Now, I am not personally a great believer in asserts. As they are runtime
checks, they require computing cycles, which is just a no-no for a bignum
library. The other option is to turn them off when not testing code. However,
this simply leads to the asserts rarely being run when they are needed.
The other problem with asserts is that they pollute the code, making the
source files longer and appear more complex.
However, there is one situation where I believe they can be very helpful,
and that is in checking the interface of functions within a library and that
it is being respected both in intra-library calls and by the test code for
the library.
Specifically, assert are useful for checking that valid inputs have been
passed to the functions, e.g. you might have a restriction that a Hensel
modulus be odd. Adding an assert allows you to test that all the moduli
you pass to the function in your test runs are in fact odd.
The main advantage in putting asserts into the code is that it forces you
to think through what all the conditions should be that you assert. In
adding asserts to the code in bsdnt I discovered one function in which the
test code was pushing the code to do things I didn't write it to cover.
This forced me to either rewrite the test, or drop that as a condition (I
think I chose the former for consistency with other related functions in
bsdnt).
Of course we do not want to consume cycles when the library is run by the
end user, and so we make asserts optional. This is done using a configure
switch. By default the macro WANT_ASSERT is set to 0 in a file config.h by
configure. However, if the user passes the option -assert to configure, it
sets the value of this define to 1.
A macro ASSERT is then defined in helper.h which is either an empty macro
in the default case or is an alias for the C assert function if WANT_ASSERT
is set to 1 in config.h.
Of course we have to remember to turn asserts on to run the test code, and
this really highlights their main weakness. As I mentioned, the asserts I
added did clarify the interface, but I don't believe they showed up any
bugs in bsdnt. With this expectation, asserts can be a useful tool.
The code for today's update is here: v0.19
Previous article: v0.18 - printx_word, nn_printx
Next article: v0.20 - redzones
No comments:
Post a Comment