From: steve@taumet.com (Steve Clamage)
Subject: Re: Functions Within Functions
Organization: TauMetric Corporation
Date: Thu, 30 Jul 1992 16:27:55 GMT

elias@proxxi.se (Elias M}rtensson (proxxi)) writes:

>amorgan@Xenon.Stanford.EDU (Crunchy Frog) writes:

>>In article <Bs5w39.5ox@news.larc.nasa.gov> 
>>  wjb@cscsun2.larc.nasa.gov (William J. Bene) writes:

>>>Is there any way to declare functions within another function like in pascal?

>>Not according to ANSI C.  GCC 2.x allows you to do it so you can use
>>that (beware, it is still fairly buggy).  BTW - Why do you want to
>>do this?  Occasionally I imagine it might be useful for encapsulating
>>code, but if a function is used in only one place I make it static
>>and avoid the problem that way (and have portable code). 

>Well, there ARE occations one might want to have encapsulated functions.
>If You make a library which uses lots of functions, there might be
>function name collisions, since You can have several encapsulated
>functions with the same name, You won't have these problems.

But if you make those functions static, you should not have any problems
with collisions.  The names of the static functions are not visible
outside the compilation unit (module) where they are defined, and you
should not really have unrelated "encapsulations" in the same module.

Pascal had nested functions in part because it did not have separate
compilation.  (Standard Pascal still does not, a factor which IMHO
prevented it from becoming more popular.)  This allowed source modules
to have local functions, and minimize problems of name collision
when combining modules.

Static functions in C pretty much eliminate this need for nested functions.

The other reason for nested functions is lexical closure, the ability
to call a function in its own nested context.  The compiler keeps
track of the function's runtime context for you, and you don't need
to have long parameter lists or pass around complicated structures.

Simple example, assuming a Pascal which supports separate compilation:

    procedure process(function gc: char); external;

    procedure fmaster(var f: text);

      function getchar: char; {function with no parameters returning char}
      var c: char;
      begin
	{ reads file 'f', the parameter to 'fmaster' }
	read(f, c);
	getchar := c;
      end;

    begin {fmaster}
      process(getchar);
    end; {fmaster}

    procedure smaster(var s: string);

      function getchar: char; {function with no parameters returning char}
      begin
	{ reads string 's', the parameter to 'smaster' }
	getchar := s.data[s.next];
	s.next := s.next + 1;
      end;

    begin {smaster}
      process(getchar);
    end; {smaster}

Here we have a separately-compiled module with procedures 'fmaster'
and 'smaster', and another with procedure 'process'.  'process' takes
a function as a parameter, and it is passed local function 'getchar'.
All that 'process' knows is that it gets passed a function which
somehow gets a character from somewhere.

Note that 'fmaster' can be called with a different file parameter each
time, and each time the current file (from the current invocation of
'fmaster') is used when 'getchar' is called back.

Similarly, 'smaster' can be called with different strings, and each
time 'getchar' is called back from 'process', the string from the
current invocation of smaster is used.

This is pretty hard to do in C.  The 'getchar' functions would have
to take a file or string parameter, meaning that the 'process' would
have to know that and pass the right thing to the right function.
Auxiliary variables would be needed to keep track of what was current.
If you added a new kind of 'master' routine, with a different way of
getting characters, 'process' and various interfaces would have to be
updated as well.  This is a maintenace nightmare.  In the Pascal
version, you could write an independent new version of a 'master' and
link it in with no other changes.

In C++, of course, you would write a hierarchy of classes with a
virtual 'getchar' function.  You add new classes with new versions
of 'getchar' without touching (or even recompiling) other code.
The need for lexical closure is less, but there are still examples
which are hard to do even in C++.
-- 

Steve Clamage, TauMetric Corp, steve@taumet.com
Vice Chair, ANSI C++ Committee, X3J16