[comp.std.c] functions within functions

garry@ithaca.uucp (Garry Wiegand) (01/22/91)

When the C standards committee was meeting, did they discuss allowing 
the declaration of functions within functions? Ie, making:

    void outside(void) { 
    	static void inside(void) {}
       	inside(); 
    }

count as legal C? Neither my quasi-Ansi C nor my g++ compiler will
accept it.

The name-space advantages should be obvious, and as far as I can
see the syntax and semantics are clear and unambiguous, with no
unfortunate side effects. (Except: I'm not sure if the word "static"
would have any meaning in the context.)  

So I'm guessing that if they thought about it they must have decided 
not to break old compilers that were strongly "moded" inside. Or
that there was some theological argument. Does anyone know? 

Put it on the list for next time. 

(The prohibition in C++ seems silly considering that a simple wrapper:

    void outside(void) {
        class wrapper {public:
            static void inside(void){}
        };
        wrapper::inside();
    }

turns it into a legal program.)

Garry Wiegand    ---    Ithaca Software, Alameda, California
...!uunet!ithaca!garry, garry%ithaca.uucp@uunet.uu.net

dave@cs.arizona.edu (Dave P. Schaumann) (01/22/91)

In article <1991Jan22.081057.8567@ithaca.uucp> garry@ithaca.uucp (Garry Wiegand) writes:
|When the C standards committee was meeting, did they discuss allowing 
|the declaration of functions within functions? Ie, making:
|
|    void outside(void) { 
|    	static void inside(void) {}
|       	inside(); 
|    }
|
|count as legal C? Neither my quasi-Ansi C nor my g++ compiler will
|accept it.

C has never allowed nested function definitions.  I don't know for sure why,
but I would guess (given that C is intended for generating clean, fast code)
that they didn't want to get involved with closures.

|Garry Wiegand    ---    Ithaca Software, Alameda, California
|...!uunet!ithaca!garry, garry%ithaca.uucp@uunet.uu.net


Dave Schaumann		|  And then -- what then?  Then, future...
dave@cs.arizona.edu	|  		-Weather Report

gwyn@smoke.brl.mil (Doug Gwyn) (01/24/91)

In article <1991Jan22.081057.8567@ithaca.uucp> garry@ithaca.uucp (Garry Wiegand) writes:
>When the C standards committee was meeting, did they discuss allowing 
>the declaration of functions within functions?

It was proposed, but since X3J11 was not trying to invent lots of
features, but rather just standardize existing practice, there was
little support for the proposal.

lindsay@gandalf.cs.cmu.edu (Donald Lindsay) (01/27/91)

In article <1991Jan22.081057.8567@ithaca.uucp> 
	garry@ithaca.uucp (Garry Wiegand) writes:
>When the C standards committee was meeting, did they discuss allowing 
>the declaration of functions within functions?
>The name-space advantages should be obvious,...

Some of us have used languages that allowed this, and didn't like it.

Personal opinion: the outer functions get unreadable.

Software engineering opinion: the inner ones get undocumented or even
unexpected side effects, because they modify global variables.
(Global to them, that is.) 

Compiler writer's opinion: the calling convention now has to support
uplevel addressing. This is typically done at a cost of at least one
extra instruction per call. This distributed overhead is paid by all
calls - not just the ones that plan to uplevel-address - unless your
compiler does interprocedural optimization.
-- 
Don		D.C.Lindsay .. temporarily at Carnegie Mellon Robotics

sef@kithrup.COM (Sean Eric Fagan) (01/27/91)

In article <11681@pt.cs.cmu.edu> lindsay@gandalf.cs.cmu.edu (Donald Lindsay) writes:
>Some of us have used languages that allowed this, and didn't like it.

Somewhat agreed.  It *can* be useful at time, but having static functions
pretty much obliviates the needs, as far as I'm concerned.  (With nested
functions, you get lots and lots and *lots* of new scoping rules, which are
a real bitch to deal with, both as a user and as a compiler writer.  Ugh.)

>Personal opinion: the outer functions get unreadable.

Agreed.  And where do you allow their declaration?  Is

	void foo(int i) {
		int j;
		int strlen(int i) { return i/j; }
		int k;
		...
	}

legal, or do you only allow a window (a la pascal) for declaring functions?
Pascal had the advantage that it is a bit more readable as a result of the
restriction, but at the hindrance of the programmer's flow of thoughts.
(And, of course, the same can be said about C's requirement on variable
declaration; and I think the code is more readable, but disrupts
flow-of-thought.)

>Compiler writer's opinion: the calling convention now has to support
>uplevel addressing. 

Actually, that's not a terrible problem.  How to deal with nested call
frames is very well understood, as are the optimisations you can do on them.
But it's still a mess.

Note, incidenlty, that Metaware's HighC allows nested functions, and gcc 2.0
will also allow them.  Both compilers allow taking the address of a nested
function, but HighC added to the syntax of the language to do so, whereas
gcc just uses the same syntax (and notes what you're doing).

As for the original question:  the committee's job was to *standardize* C.
Very few C compilers allowed nested functions, and none of the books
describing the language "C" allowed for them.  It was not in the language.
My usual point for this type of thing is to bring up two things that ANSI
introduced to C:  prototypes, which most people agree are good, but still
have problems with%, and trigraphs, which almost nobody likes, including the
people who need them.

-----
% Given:
int foo(char);
int foo(i) char i; { return i; }

gcc (correctly) gives an error (unless -traditional is used, I believe);
most other compilers accept it (maybe warning about it at a certain level),
but not by default.
-----

-- 
Sean Eric Fagan  | "I made the universe, but please don't blame me for it;
sef@kithrup.COM  |  I had a bellyache at the time."
-----------------+           -- The Turtle (Stephen King, _It_)
Any opinions expressed are my own, and generally unpopular with others.

dave@cs.arizona.edu (Dave P. Schaumann) (01/28/91)

This does bring up a problem that should be adressed:
  As it stands, C has two scopes where functions can be seen:
	1. Static (ie, within a file)
	2. Global (everywhere)

It would be nice if there were a device that allowed user-definable
scopes that function names would be visible in.  Hmm.  It occurs to me
that C++'s class keyword allows just that...  Maybe a simplified form
of this mechanism should be considered for addition.  Thus, you could
type something like

bar::foo( int baz ) { ... }

bop::foo( char *glorp ) { ... }

With no conflict.  Of course, you would have to include the scope-space
keyword to disambiguate a function call to foo().

Dave Schaumann		|  And then -- what then?  Then, future...
dave@cs.arizona.edu	|  		-Weather Report

jimad@microsoft.UUCP (Jim ADCOCK) (01/29/91)

In article <1991Jan22.081057.8567@ithaca.uucp> garry@ithaca.uucp (Garry Wiegand) writes:
|When the C standards committee was meeting, did they discuss allowing 
|the declaration of functions within functions? Ie, making:
|
|    void outside(void) { 
|    	static void inside(void) {}
|       	inside(); 
|    }
|
|count as legal C? Neither my quasi-Ansi C nor my g++ compiler will
|accept it.
|
|The name-space advantages should be obvious, and as far as I can
|see the syntax and semantics are clear and unambiguous, with no
|unfortunate side effects. (Except: I'm not sure if the word "static"
|would have any meaning in the context.)  
|
|So I'm guessing that if they thought about it they must have decided 
|not to break old compilers that were strongly "moded" inside. Or
|that there was some theological argument. Does anyone know? 
|
|Put it on the list for next time. 
|
|(The prohibition in C++ seems silly considering that a simple wrapper:
|
|    void outside(void) {
|        class wrapper {public:
|            static void inside(void){}
|        };
|        wrapper::inside();
|    }
|
|turns it into a legal program.)

I don't think it would be too hard to remove the requirement for 
the wrapper class -- but, that still wouldn't give people the nested
function capabilities they'd expect from playing with other languages.

In C++, the nested class [and therefore the nested function] only is 
allowed access to the type names, static variables, extern variables and
functions, and enumerations from the enclosing scope.

Even if you didn't have to write the wrapper:: prefix on inside(), 
inside() still wouldn't be able to access the auto variables of outside().
So you still couldn't do the Pascal hack of declaring inner functions
with implied parameters, for example.

Seems to me the end result would come out half-Pas'cal'ed.

rjohnson@shell.com (Roy Johnson) (02/01/91)

In article <70282@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes:
>In article <1991Jan22.081057.8567@ithaca.uucp> garry@ithaca.uucp (Garry Wiegand) writes:
>|When the C standards committee was meeting, did they discuss allowing 
>|the declaration of functions within functions? Ie, making:
>|
>|> void outside(void) { 
>|> 	static void inside(void) {}
>|>> 	inside(); 
>|> }
>|
>|count as legal C? Neither my quasi-Ansi C nor my g++ compiler will
>|accept it.
>|
>|The name-space advantages should be obvious, and as far as I can
>|see the syntax and semantics are clear and unambiguous, with no
>|unfortunate side effects. (Except: I'm not sure if the word "static"
>|would have any meaning in the context.)  

If you're worried about the namespace, just make different code
modules, where the outside() is available to the other modules,
and inside() is only available within outside()'s module.

--
======= !{sun,psuvax1,bcm,rice,decwrl,cs.utexas.edu}!shell!rjohnson =======
"If he exploded, all of Manhattan would be talking in high, squeaky voices
for months!"  "Cool." -- When I Was Short
Roy Johnson, Shell Development Company

datangua@watmath.waterloo.edu (David Tanguay) (02/09/91)

One of the "problems" with adding nested functions to C is the addition
of a display to access autos in outer scopes. The whole issue could be
avoided by not having autos imported into functions.
E.g.:

	int f( int a )
	{
		static int b;
		auto int c;
		int g( int d )
		{
			b = d+1;	/* is okay */
			c = 0;	/* error: c is not in scope */
			return d * b;
		}
		c = g( a + b );
		return 3 * c + 2;
	}
	/* g is not visible here */

This results in scoping rules similar to Port (a cousin of C -- B->Zed->Port,
I believe).

Additional idea:
	an auto function is not visible to inner functions, static function is
-- 
David Tanguay            Software Development Group, University of Waterloo

rex@aussie.COM (Rex Jaeschke) (02/10/91)

> Re: functions within functions

MetaWare's High C has had nested functions now probably for 4-5 years. 
(Interestingly, MetaWare is/was a big user of Pascal, and High C versions 
earlier than the most recent one were actually written in their extended 
Pascal.)

I documented their nested function extension (along with several other 
extensions) in Vol 2, num 3 (Dec 1990) of The Journal of C Language 
Translation on page 240. (Their very interesting iterator extension is 
covered in Vol 2/4 in Mar '91.)

To add nested functions they use ! as a postfix punctuator in function 
declarations. Late in 1990 Bjarne Stroustrup proposed using this notation 
to solve a problem re alternate trigraphs at the ISO C level. As such, I 
informed him this conflicted with MetaWare's prior art.

Rex

----------------------------------------------------------------------------
Rex Jaeschke     |  Journal of C Language Translation  | C Users Journal
(703) 860-0091   |        2051 Swans Neck Way          | DEC PROFESSIONAL
rex@aussie.COM   |     Reston, Virginia 22091, USA     | Programmers Journal
----------------------------------------------------------------------------
Convener of the Numerical C Extensions Group (NCEG)
----------------------------------------------------------------------------

garry@ithaca.uucp (Garry Wiegand) (02/11/91)

In article <1991Feb8.232835.19022@watmath.waterloo.edu> datangua@watmath.waterloo.edu (David Tanguay) writes:
>One of the "problems" with adding nested functions to C is the addition
>of a display to access autos in outer scopes. The whole issue could be
>avoided by not having autos imported into functions.
>...
>			b = d+1;	/* is okay */
>			c = 0;	/* error: c is not in scope */

Exactly! Doesn't hurt, gives people like me another level of function
name-scoping, and if at some later time the community wants to add
access to outer autos and parameters ("closure", as someone
explained to me), that would be upward-compatible.

I have seen the innards of compilers like the old 'pcc': they are
really badly written, with lots of mode variables declared globally.
*Not* structured/modular/defensive. In a well-written compiler you
would probably have to make an extra check to *disallow* functions-
in-functions. 

I wonder how many of the representatives on the standards committee
have "well-written compilers"...

>Additional idea:
>  an auto function is not visible to inner functions, static function is.

Hmmmm...

Garry Wiegand    ---    Ithaca Software, Alameda, California
...!uunet!ithaca!garry, garry%ithaca.uucp@uunet.uu.net

jfh@rpp386.cactus.org (John F Haugh II) (02/11/91)

In article <1991Feb11.090514.5736@ithaca.uucp> garry@ithaca.uucp (Garry Wiegand) writes:
>I have seen the innards of compilers like the old 'pcc': they are
>really badly written, with lots of mode variables declared globally.
>*Not* structured/modular/defensive. In a well-written compiler you
>would probably have to make an extra check to *disallow* functions-
>in-functions. 

I would say a well written compiler would still have to add something
to permit function definitions within a function.

There are definitions which are not permitted inside of a function,
such as definitions containing initialized aggregates, as well as
ones which are forbade outside of functions, such as automatic
variables (does anyone use "auto" anymore???)

If the parser does not faithfully implement the syntax of the language,
I'd say something is seriously wrong, even if the code is "structured",
or whatever.  The syntax elements <function-definition> and
<automatic-variable-definition> had best not be lumped into the single
syntax element <some-kind-of-definition>.
-- 
John F. Haugh II                             UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832                           Domain: jfh@rpp386.cactus.org
"I've never written a device driver, but I have written a device driver manual"
                -- Robert Hartman, IDE Corp.