Assertions

karlnapf edited this page Oct 25, 2014 · 13 revisions
Clone this wiki locally

Lots of times, we want to make sure certain conditions in the code, such as range bounds on variables, non-negative indices, matching vector/matrix sizes, parameters in [0,1], etc. There are two different cases to check:

  1. User specified inputs. I.e. when users have the power to break these conditions
  2. Internal checks. I.e. when the user is not able to break the condition, but you want to make sure that things are working in your code

First of all, number 2. is not necessary at all. It is just for your convenience. You should rather write proper unit-tests for your code than being lazy and relying on assertions to check whether things are working correctly.

For the other one: Although we have an ASSERT macro, please try to avoid it where possible. Imagine there is code like

void foo(index_t i)
{
...
ASSERT(i>=0);
...
}

All the user will get when running Shogun is an assertion error. If he is brave and turns on printing line and file of the error, the information is very sparse, resulting in frustration.

Instead, use the REQUIRE macro, and give proper error messages, which means information of what is wrong, and in particular how it differs from what was expected. Example

void foo(index_t i, SGVector<index_t> inds)
{
...
REQUIRE(i>=0, "Provided index (%d) must be greater than 0.\n", i);
...
REQUIRE(inds.vlen==this->bar.vlen, "Provided index vector length (%d) must match the length of internal vector (%d).\n", inds.vlen, this->bar.vlen);
}

Note that you do not need to type class or method name, this can all be done by the user via for example any_shogun_object->io->set_location_info(location), where location can be one of MSG_NONE, MSG_FUNCTION, MSG_LINE_AND_FILE, see SGIO class.

Finally

  • Use proper English (Start with capital letters, write sentences)
  • Don't forget \n at the end.
  • Make sure that you don't cause segfaults in your assertions, check bounds, pointer valid, etc
void foo(SGVector<index_t> inds)
{
...
// First check makes sure that second check does not segfault
REQUIRE(inds.vlen>=1, "Length of provided vector (%d) must be at least 1.\n", inds.vlen);
REQUIRE(inds[0]>0, "First element of provided vector (%d) must be greater than 0.\n", inds[0]);
}
void foo(CKernel* kernel)
{
...
// First check makes sure that second check does not segfault
REQUIRE(kernel, "No kernel provided.\n");
REQUIRE(kernel->get_width()>=1, "Provided kernel width (%f) must be greater than 1.0.\n", kernel->get_width());
}