Eric Sosman said:
The specifications are too weak to drive implementations.
What does xmalloc() do when unable to allocate memory? Does
replace() replace all occurrences, or just the first, or just
the last, or what? What does getquote() do with unbalanced
quotes? Does getline() keep or discard the '\n', and what does
it do on an I/O error? (See the recent thread on design of line-
input functions to see how divergent people's opinions are on
how this "familiar friend" should behave.)
... and massively complicates error handling. If xmalloc()
can unilaterally terminate the program, the whole suite is
unusable except in toy programs. If there's a fancier framework,
all functions that use the suite or that call other functions
that might use the suite need to be plugged in to the framework.
Design consists of more than writing a few declarations.
I usually use a garbage collector.
if the app runs out of memory (rare, since I usually use primarily static
memory-management approaches, but I can be lazy sometimes), the allocator
returns NULL.
now, crashing the app is just lazy, but it is possibly justified on the
grounds that on modern systems, running out of memory is rare enough that
this is justified (actually, it may well be justified to crash the app
before this limit, setting some sort of critical upper bound on memory
usage, and provoking the dev to reduce the footprint).
however, often NULL works just as well, because, as a general rule accessing
memory through a NULL pointer will crash the app anyways (most of the time,
address 0 being set to no-access).
this would be, assuming the issue is not handled.
better though, would be an exception handling system, namely, we crash only
if the out-of-memory exception goes unhandled. now, this is less nice in C,
which lacks a good exception system (nor the language features to really
implement one).
that is not to say, however, that a crude one could not be built around
setjmp/longjmp (library feature), or could be added, for example, as a
compiler syntax extension that rewrites exception handlers into the library
feature's form.
thus, in this case, an unhandled exception thus results in an abort (sadly,
an actual 'crash' at this point is pointless, since the context of the
exception is already lost).
of course, another approach would be threaded or recursive exception
handling (in C, however, there would be present other problems, and
semantics which would be problematic to reconcile with the unwinding
variety).
the system could, likely, be made to handle both, with some handlers set to
behave in a recursive manner (more like signal) and others in an unwinding
manner (longjmp). for semantic reasons, likely an unwinding handler would
silently ignore any previous recursive handlers (them being invoked in an
essentially meaningless context).
throw:
if last handler is signal-style, invoke callback;
otherwise, unwind to last handler.
handler:
if correct exception, do handling actions, and resume execution post
handler;
if there is another unwinding handler, unwind to that handler;
else, rethrow an unhandled exception.