The advantage of garbage collection for APIs
Here's a question that interests me: why don't I have
a standard C version of my Python
warn() function? The Python version shows up in most
programs I write, but in my C programs I generally directly
errors to stderr, instead of having a utility function for it.
Part of the reason is that a C version of
warn() really calls for a
different and more complicated set of arguments. Instead of a single
string, the natural C-ish approach is printf()-like, creating a
prototype of '
warn(const char *fmt, ...)'. In turn this makes
a non-trivial function, because varargs functions in C are vaguely
(Things get even more interesting when one implements
die(), since you
can't have it call
warn(); either you duplicate
warn()'s code or you
wind up needing a
vwarn() with the prototype '
vwarn(const char *fmt,
va_list ap)' that both
But why does the C version of
warn() need a different API than the
Python one? One answer is that Python has a first class operator to
format printf-like strings (the string '
%' operator, in a marvelous
abuse of operator overloading) and C doesn't, so in Python it's
idiomatic to format strings directly in your code, instead of handing
the format and the arguments to another function. This isn't the whole
story, though, since C has
sprintf() and could do much of the same
tricks if people wanted to.
The problem with
sprintf() (and why in practice it is not used for
this) is that you have to give it a buffer. If you use
you have to think about how big a buffer you need and what you do if it
isn't big enough. If you use
fprintf(), you don't have to think about
all of that, so people use
fprintf(); in C, people will go to a lot of
effort to avoid having to think about buffer issues.
And the reason that
sprintf() needs you to supply the buffer is so
that no one has to worry about allocating and especially deallocating
the buffer, because memory management is a pain in the rear in
C. Not just because you have to do it, but also because you have to
decide where it's done and which function has to look after it and
this generally complicates the code. (For example,
just free the string it's passed, which means that you can't write
warn(strformat(fmt, ...))' because this leaks the string.)
Thus I come to the conclusion:
A subtle advantage of garbage collection is that it enables APIs that would otherwise be impossible, or at least dangerous.
Garbage collection is the essential glue that enables my Python versions
die() to have their simple APIs, because it is what
makes Python's '
%' operator convenient (among many other Python APIs).
You could implement all of the operations of the Python version in C,
but you shouldn't; in a non-GC'd language, object allocation is to be
avoided as much as possible, and certainly turned into someone else's
sprintf() does not allocate anything; finding a buffer for
it is your problem.)