Pre / post conditions in error handling

8 views
Skip to first unread message

Dave

unread,
Jul 21, 2004, 8:05:19 AM7/21/04
to

Hello all,

I found Herb Sutter's article regarding error handling in the most recent
CUJ to be very, very good. However, in trying to apply what I learned from
the article, I am left with some questions.

I have a function that takes a std::string (that represents a file name) as
a parameter. This function reads in the contents of the file and returns a
struct representing the file's content.

Two things could go wrong inside the function:

1. The function might find that the file does not exist
2. The function might find that the content of the file is invalid

(Some might consider 1 to be a special case of 2.)

The question is: Are these cases a violation of the function's preconditions
or postconditions? According to the error handling philosophy advocated by
Herb in his article, if it is a precondition violation, it should have been
reported as an error in the calling function. Since it wasn't, we should
report a program bug via an assert in the called function. If it is a
postcondition violation, it should be reported as an error in the called
function. Since whether the problem is a precondition or postcondition
problem determines where the error gets reported, it is something I need to
know to properly write my code.

I can reason that these are precondition violations since it seems
justifiable to say that a precondition for the function is that the file
both exist and have valid content.

However, I can also make a reasonable argument that it is a postcondition
violation since the function cannot construct a valid return value. In this
case, the precondition would be nothing more than that the string object
passed in be valid. If it's a valid std::string, the precondition is met,
period.

So, I need a little more guidance than that provided in the article as to
how to classify a problem as a precondition or postcondition violation. I'm
thinking that perhaps it is a subjective thing and that either way you go
could be OK as long as you're consistent. All help will be appreciated!

Thanks,
Dave

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Niklas Matthies

unread,
Jul 21, 2004, 3:56:55 PM7/21/04
to
On 2004-07-21 12:05, Dave wrote:
:

> I can reason that these are precondition violations since it seems
> justifiable to say that a precondition for the function is that the
> file both exist and have valid content.
>
> However, I can also make a reasonable argument that it is a
> postcondition violation since the function cannot construct a valid
> return value. In this case, the precondition would be nothing more
> than that the string object passed in be valid. If it's a valid
> std::string, the precondition is met, period.
>
> So, I need a little more guidance than that provided in the article
> as to how to classify a problem as a precondition or postcondition
> violation. I'm thinking that perhaps it is a subjective thing and
> that either way you go could be OK as long as you're consistent.
> All help will be appreciated!

I haven't read Herb Sutter's article, but: A precondition makes only
sense if the client code has a realistic chance to reliably ensure it
_and_ if ensuring the precondition doesn't involve performing a
non-trivial portion of what is supposed to be the function's job.

Ensuring that a file exists typically cannot be reliably achieved, so
this really isn't a good candidate for a precondition. Ensuring that a
structure to be parsed is well-formed is generally no problem (unless
the structure is read-once or may change between reads), but inherently
requires parsing it, so it would be rather pointless to have this as a
precondition of a function that does the parsing anyway (as part of
its publicly known functionality).

-- Niklas Matthies

David Abrahams

unread,
Jul 21, 2004, 4:04:20 PM7/21/04
to
"Dave" <better...@yahoo.com> writes:

> Hello all,
>
> I found Herb Sutter's article regarding error handling in the most recent
> CUJ to be very, very good. However, in trying to apply what I learned from
> the article, I am left with some questions.
>
> I have a function that takes a std::string (that represents a file name) as
> a parameter. This function reads in the contents of the file and returns a
> struct representing the file's content.
>
> Two things could go wrong inside the function:
>
> 1. The function might find that the file does not exist
> 2. The function might find that the content of the file is invalid
>
> (Some might consider 1 to be a special case of 2.)
>
> The question is: Are these cases a violation of the function's preconditions
> or postconditions?

That's up to the author of the function, who writes the function's
documentation, including its preconditions and postconditions.

Now if the question is, "how do I decide what should be a
precondition?", you have to ask what's reasonable to ask the caller to
ensure. Some conditions are best _not_ made preconditions because
ensuring that they're satisfied is almost as expensive as the
operation to be performed. That's the case with file content validity
-- you have to read the whole thing just to validate it. In your
example, even if the caller *did* ensure that the file existed and was
valid, unless the process holds exclusive write access on the file, on
most OSes some other process could come in and change either of those
conditions. So it's unlikely that you can meaningfully make 1 or 2 a
precondition.

You also can't make them postconditions, for the same reasons: another
process could come in and delete the file as the called function is
returning. However, if 1 and 2 are not satisfied, they will affect
the called function's ability to satisfy its own postconditions. So
throwing an exception or otherwise reporting an error to the caller is
appropriate here, and asserting is not.

HTH,
--
Dave Abrahams
Boost Consulting
http://www.boost-consulting.com

Herb Sutter

unread,
Jul 22, 2004, 7:19:55 AM7/22/04
to

On 21 Jul 2004 16:04:20 -0400, David Abrahams <da...@boost-consulting.com>
wrote:

>Now if the question is, "how do I decide what should be a
>precondition?", you have to ask what's reasonable to ask the caller to
>ensure.
[...]

>However, if 1 and 2 are not satisfied, they will affect
>the called function's ability to satisfy its own postconditions. So
>throwing an exception or otherwise reporting an error to the caller is
>appropriate here, and asserting is not.

Dave's answer is exactly correct. To restate very slightly: 1 and 2 are
not in themselves postconditions, but they are presumably essential[*]
steps for the function to achieve its postconditions, and hence their
failure constitutes an error.

[*] unless the function has some alternative way to do its work if 1
and/or 2 fail, such as providing graceful fallback to a degraded but still
correct mode; this seems not to be the case in your example

Herb


---
Herb Sutter (www.gotw.ca)

Convener, ISO WG21 (C++ standards committee) (www.gotw.ca/iso)
Contributing editor, C/C++ Users Journal (www.gotw.ca/cuj)
Visual C++ architect, Microsoft (www.gotw.ca/microsoft)

Peter Schneider

unread,
Jul 22, 2004, 7:25:22 AM7/22/04
to
Hi,

"Dave" <better...@yahoo.com> wrote

> I found Herb Sutter's article regarding error handling in the most recent
> CUJ to be very, very good. However, in trying to apply what I learned
from
> the article, I am left with some questions.
>
> I have a function that takes a std::string (that represents a file name)
as
> a parameter. This function reads in the contents of the file and returns
a
> struct representing the file's content.
>
> Two things could go wrong inside the function:
>
> 1. The function might find that the file does not exist
> 2. The function might find that the content of the file is invalid
>
> (Some might consider 1 to be a special case of 2.)
>
> The question is: Are these cases a violation of the function's
preconditions
> or postconditions?

I haven't read the article either, but ...

... you already say "1." and "2." The function performs two tasks that are
at second sight largely independent: 1. Opening a file; 2. parsing its
content.

This division would provide for reading different data sources; the parsing
part is not concerned about what the descriptor/file pointer/stream is
connected to. This division/abstraction may support future enhancements
(e.g. read from a socket or a preprocessor pipe). The validity of the "file
handle" parameter then *is* a precondition for the parsing function, imo.

The precondition of the file opening function is indeed only a valid string.
As David Abrahams pointed out, opening the file may fail for external
reasons; but once opened, it should be "indestroyable" on a modern OS, under
regular conditions; therefore I think that the validity of the handle is a
valid postcondition for the opening function.

Regards, Peter

Reply all
Reply to author
Forward
0 new messages