D
Don Y
Hi,
[Please take the time to understand what I'm looking for before
replying. I've spent a lot of time describing it; it would
be courteous for you to make a similar investment before
commenting on it.]
I have a suite of projects that utilize a common approach to
error reporting. Instead of a PASS/FAIL result, most functions
return information regarding the nature of the "failure" (which
can also include "partial failures"... "warnings"). These
reports allow upper levels of the application to convey those
details to the user without exposing all of the *mechanism*
involved to those upper levels.
E.g., the application may need a numeric value from the user
with a particular set of constraints (must be positive, less
than 293, no more than two decimals, etc.). Of course, it would
be silly for the upper levels of the application to process
individual characters to assemble such a "value" and enforce
those constraints.
Instead, you'd wrap the behavior in a function that you could
reuse wherever similar needs arise. That function would be
parameterized to allow the caller to specify the constraints
that need to be applied. It would return the value retrieved
from the user or an indication of problems encountered in
the parsing of that value -- constraint violations.
[Note that "from the user" could just as easily be "from a
file"... i.e., how the error is ultimately reported/handled
is something that the upper level routines should decide,
not this lower level function]
For example, the lower level routine might report:
- invalid character encountered
- value below minimum allowed
- value exceeds maximum allowed
- too many significant digits
The "invalid character" report might be embelished:
- only one decimal point allowed
- only one *sign* allowed
- non-digit encountered
Etc. The information conveyed by each of these allows the
application to inform the user of the exact nature of the
"problem" -- instead of just resorting to a "bad value"
report.
Each possible "report" needs a mechanism through which the
caller can ascertain the nature of the error. You *could*
impose a convention that causes reports to be more easily
summarized: e.g., 0 for SUCCESS, <0 for errors, >0 for
warnings (so, if you don't care about warnings the caller
would test for any "not negative" result codes as being
"acceptable" -- as in the case of SUCCESS or "too many
significant digits").
Of course, there's nothing difficult or magical about this.
Create an enumeration or a set of manifest constants to
symbolically represent each of the "results", package them
in a header file and you're all set!
That approach is fine for "small" functions with a limited
number of potential "results". But, consider how you would
scale it to more comprehensive functions. E.g., the complete
UI. Managing these "enumerations" gets to be tedious and
error prone. "Which *values* have been assigned? What is
a good value to pick for this new 'condition'? etc."
One approach to ensuring unique "values" for each of these
"results" is to synthesize them from the function/file name
and line number where they are detected (instantiating a
macro at that particular point). This ensures that values
are unique while hiding the *actual* value from the developer
(*I* surely don't care if TOO_MANY_DECIMAL_POINTS resolves
to 0x27 or 0x7732!).
The problem then becomes one of making that information available
to other *consumers*! I.e., wrapping it in a header file that
others can reference.
[Note this opens the door for a bootstrap problem but I am
willing to live with that -- "I'll deal with it later..."]
A "solution" also needs to address the problem of *explaining*
the "result" (to the ultimate user). The point at which the
result is "signaled" contains the most information about the
nature of the "problem" being reported though it is in a
very narrowly defined context: i.e., you can tell the user
"Multiple decimal points encountered" -- though you can't
indicate the role that the value being entered plays in the
application (is this a person's wages? the weight of a
newborn child? the average lifespan of a male tortoise?).
So, the developer should be able to tie the explanation/commentary
*to* the (symbolic) result code where the result code is defined
instead of having to do so "somewhere else" -- hoping to keep the
explanations in sync with the symbolic names, etc.
A code fragment with such a system might look like:
if (*ptr == '.') {
if (decimalPointEncountered == TRUE) {
MakeErrorCode(Err_TooManyDecimalPoints,
"Multiple decimal points encountered.",
"Only a single decimal point is allowed in numeric
values."
)
result = Err_TooManyDecimalPoints;
} else {
decimalPointEncountered = TRUE;
}
}
...
return (result);
Obviously, a macro could #define Err_TooManyDecimalPoints to a unique
value, here (e.g., __FILE__ ## __LINE__). A script could parse the
output of the preprocessor extracting all lines of the form
"#define Err_" to build a suitable header file. And, another
script could extract the short and long textual explanations of
the error itself.
I currently do this with a mix of ad hoc measures. As such,
it is very fragile (and an annoying drain on my time!). I'm
hoping for suggestions that might lead me to a better/different
approach (WITH THE SAME GOALS). Pointers to tools better suited
to this. *Or*, examples of similar approaches!!
Thx,
--don
[Please take the time to understand what I'm looking for before
replying. I've spent a lot of time describing it; it would
be courteous for you to make a similar investment before
commenting on it.]
I have a suite of projects that utilize a common approach to
error reporting. Instead of a PASS/FAIL result, most functions
return information regarding the nature of the "failure" (which
can also include "partial failures"... "warnings"). These
reports allow upper levels of the application to convey those
details to the user without exposing all of the *mechanism*
involved to those upper levels.
E.g., the application may need a numeric value from the user
with a particular set of constraints (must be positive, less
than 293, no more than two decimals, etc.). Of course, it would
be silly for the upper levels of the application to process
individual characters to assemble such a "value" and enforce
those constraints.
Instead, you'd wrap the behavior in a function that you could
reuse wherever similar needs arise. That function would be
parameterized to allow the caller to specify the constraints
that need to be applied. It would return the value retrieved
from the user or an indication of problems encountered in
the parsing of that value -- constraint violations.
[Note that "from the user" could just as easily be "from a
file"... i.e., how the error is ultimately reported/handled
is something that the upper level routines should decide,
not this lower level function]
For example, the lower level routine might report:
- invalid character encountered
- value below minimum allowed
- value exceeds maximum allowed
- too many significant digits
The "invalid character" report might be embelished:
- only one decimal point allowed
- only one *sign* allowed
- non-digit encountered
Etc. The information conveyed by each of these allows the
application to inform the user of the exact nature of the
"problem" -- instead of just resorting to a "bad value"
report.
Each possible "report" needs a mechanism through which the
caller can ascertain the nature of the error. You *could*
impose a convention that causes reports to be more easily
summarized: e.g., 0 for SUCCESS, <0 for errors, >0 for
warnings (so, if you don't care about warnings the caller
would test for any "not negative" result codes as being
"acceptable" -- as in the case of SUCCESS or "too many
significant digits").
Of course, there's nothing difficult or magical about this.
Create an enumeration or a set of manifest constants to
symbolically represent each of the "results", package them
in a header file and you're all set!
That approach is fine for "small" functions with a limited
number of potential "results". But, consider how you would
scale it to more comprehensive functions. E.g., the complete
UI. Managing these "enumerations" gets to be tedious and
error prone. "Which *values* have been assigned? What is
a good value to pick for this new 'condition'? etc."
One approach to ensuring unique "values" for each of these
"results" is to synthesize them from the function/file name
and line number where they are detected (instantiating a
macro at that particular point). This ensures that values
are unique while hiding the *actual* value from the developer
(*I* surely don't care if TOO_MANY_DECIMAL_POINTS resolves
to 0x27 or 0x7732!).
The problem then becomes one of making that information available
to other *consumers*! I.e., wrapping it in a header file that
others can reference.
[Note this opens the door for a bootstrap problem but I am
willing to live with that -- "I'll deal with it later..."]
A "solution" also needs to address the problem of *explaining*
the "result" (to the ultimate user). The point at which the
result is "signaled" contains the most information about the
nature of the "problem" being reported though it is in a
very narrowly defined context: i.e., you can tell the user
"Multiple decimal points encountered" -- though you can't
indicate the role that the value being entered plays in the
application (is this a person's wages? the weight of a
newborn child? the average lifespan of a male tortoise?).
So, the developer should be able to tie the explanation/commentary
*to* the (symbolic) result code where the result code is defined
instead of having to do so "somewhere else" -- hoping to keep the
explanations in sync with the symbolic names, etc.
A code fragment with such a system might look like:
if (*ptr == '.') {
if (decimalPointEncountered == TRUE) {
MakeErrorCode(Err_TooManyDecimalPoints,
"Multiple decimal points encountered.",
"Only a single decimal point is allowed in numeric
values."
)
result = Err_TooManyDecimalPoints;
} else {
decimalPointEncountered = TRUE;
}
}
...
return (result);
Obviously, a macro could #define Err_TooManyDecimalPoints to a unique
value, here (e.g., __FILE__ ## __LINE__). A script could parse the
output of the preprocessor extracting all lines of the form
"#define Err_" to build a suitable header file. And, another
script could extract the short and long textual explanations of
the error itself.
I currently do this with a mix of ad hoc measures. As such,
it is very fragile (and an annoying drain on my time!). I'm
hoping for suggestions that might lead me to a better/different
approach (WITH THE SAME GOALS). Pointers to tools better suited
to this. *Or*, examples of similar approaches!!
Thx,
--don