Interesting. I've certainly made extensive use of nested functions
(and/or procedures) in Pascal and Ada. Perhaps there's something
about C (other than the obvious fact that the standard doesn't
support them) that makes nested functions less useful?
I don't know. The usage in question was as follows:
There's a function in glibc called rpmatch(), which basically tells
you whether a provided string looks like "yes" or "no". To do this,
it has a nested function called try().
/* Determine whether string value is affirmation or negative response
according to current locale's data.
This file is part of the GNU C Library.
Copyright (C) 1996, 1997, 2000, 2003 Free Software Foundation, Inc.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <langinfo.h>
#include <stdlib.h>
#include <regex.h>
int
rpmatch (response)
const char *response;
{
/* Match against one of the response patterns, compiling the pattern
first if necessary. */
auto int try (const int tag, const int match, const int nomatch,
const char **lastp, regex_t *re);
int try (const int tag, const int match, const int nomatch,
const char **lastp, regex_t *re)
{
const char *pattern = nl_langinfo (tag);
if (pattern != *lastp)
{
/* The pattern has changed. */
if (*lastp)
{
/* Free the old compiled pattern. */
__regfree (re);
*lastp = NULL;
}
/* Compile the pattern and cache it for future runs. */
if (__regcomp (re, pattern, REG_EXTENDED) != 0)
return -1;
*lastp = pattern;
}
/* Try the pattern. */
return __regexec (re, response, 0, NULL, 0) == 0 ? match : nomatch;
}
/* We cache the response patterns and compiled regexps here. */
static const char *yesexpr, *noexpr;
static regex_t yesre, nore;
return (try (YESEXPR, 1, 0, &yesexpr, &yesre) ?:
try (NOEXPR, 0, -1, &noexpr, &nore));
}
A bit of analysis:
It does make some sense to create a function for the "create a new
regex for this pattern, if we don't have one yet already". (The reason
for the elaborate dance to figure out whether the pattern is the same,
I think, is in case the locale changes after you've previously called this.)
It's a nested function because it wants to check the value of "response",
and apparently, while it's awesome to have a function that takes five
parameter, including one for what it should return on a match and one
for what it should return on a non-match, it is ridiculous to have a function
that takes a sixth parameter.
Had I been writing this, it would likely have been:
static int
check_response(const int tag,
const char **lastp,
const regex_t *re,
const char **response) {
/* return 1 on a match */
}
and been invoked as:
if (check_response(YESEXPR, &yesexpr, &yesre, response)) {
return 1;
} else if (check_response(NOEXPR, &noexpr, &nore, response)) {
return 0;
} else {
return -1;
}
It is amusing to me to note that the GNU C "?:" was used here. (And to
good effect, even!)
Basically, though, this is a great example of the same kind of insane
pseudo-cleverness that sandeep's example code has been such a rich source
of. The nested function is not particularly necessary. The elaborate
match/nomatch returns create an undue complication, to put it mildly.
I'm sure, somewhere, there must be legitimate uses for this extension, but
I've never seen it for anything but stuff like the above, which exists only
to be a weakest link in some piece of software with some set of compiler
options, because it's so rarely used.
-s