2

Let's say I have a function that calculates a sensor output, all values are >=0, but also I have to detect some error situations like "NO_POWER" which I encoded with value "-65500". On my application there are classes that only care for the real output value (regardless if an error is present) and other classes that needs the real value and the proper error code. So, in terms of design I came out with the idea that I need to separate the concept of "value" and "error code", I came up with 2 options:

Return value and error code in the same output (client classes will have to know how to interpreter the output value):

double Sensor::compute() {
   double output = compute();
   return output;
}

or using a structure like to retrieve the output:

struct SensorOutput {
   double value;
   int error_code;
}

so my method could look like:

SensorOutput Sensor::compute() {
   double output = compute();
   int errorCode = get_error_code();
   SensorOutput out;
   out.value = output;
   out.error_code = errorCode;
}

Which one is better in design terms?

3

First of all, I assume that using exceptions to signal those errors is out of the question (either because you do not wish to use exceptions, or those errors are considered part of the "normal" flow of the program for one reason or another).

I would strongly suggest the second approach. If you were to use a -65500 result as an code to indicate "there has been error XYZ" you are actually mixing two separate contexts: The normal result of Sensor::compute() and signaling errors. Imagine that - due to a change of requirements - Sensor::compute() suddendly should be able to return negative values... but those are now already reserved for your "error codes" - and suddently you've got a problem.

Also you need to sprinkle your code with calls along the line of

if (sensorValue == ERROR_CODE_ABC)
    //Error handling
else if (sensorValue == ERROR_CODE_DEF)
    //More Error handling
else
    doStuffWithValue(sensorValue);

And you always risk the possibility of working with an errorCode value instead of a real value, because you missed a spot for a check (new target voltage for the PSU is -65500V... ummm, not good). Alas, even the second approach cannot free you from this burden entirely - you may be able to use more sane/safe values (the sensor has NO_POWER, so the measured voltage is 0V), but you still need to check sensorValue.errorCode every time - only exceptions would be able to help you out there (if you forget to handle them somewhere, they for terminate the program, instead of letting you work with bogus values, causing hard to track errors)

1

The other approach would be boost::optional or (if your compiler supports it) std::optional. An optional may or may not have a value. I don't know if this would work as well for you as the struct, but it's less to get wrong.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.