17

It doesn't seem like it would be too hard to implement in assembly.

gcc also has a flag (-fnested-functions) to enable their use.

Alexis Wilke's user avatar
Alexis Wilke
21.3k11 gold badges111 silver badges183 bronze badges
askedAug 28, 2009 at 16:25
des4maisons's user avatar
10
  • 4
    There's a difference between what would/wouldn't be "too hard" to implement, and what the standards-defining body chose to include or omit from the standard. GCC providing support for this just means that it is something implemented outside of the scope of the standard - to wit, it is a non-standard feature. GCC is just an implementation of a compiler that adheres to the C standard; it's not limited in any way to provide only what is in the standard.CommentedAug 28, 2009 at 16:32
  • 2
    @Matt: sounds like an answer rather than a commentCommentedAug 28, 2009 at 16:33
  • Matt Ball: My question is indeed why the standards-defining body chose to omit such a feature. My reference to gcc was more of an example of "it can be done so why isn't it".CommentedAug 28, 2009 at 16:37
  • Related:stackoverflow.com/questions/666586/…CommentedAug 28, 2009 at 16:42
  • 3
    @des4maisons "It can be done so why not do it" is how you end up with languages like C++. Whether that's a good or bad thing is up to you. (and yes, C++ doesn't directly support nested functions either, but you can always make a local functor).CommentedAug 28, 2009 at 17:46

9 Answers9

13

It turns out they're not actually all that easy to implement properly.

Should an internal function have access to the containing scope's variables?If not, there's no point in nesting it; just make it static (to limit visibility to the translation unit it's in) and add a comment saying "This is a helper function used only by myfunc()".

If you want access to the containing scope's variables, though, you're basically forcing it to generate closures (the alternative is restricting what you can do with nested functions enough to make them useless).I think GCC actually handles this by generating (at runtime) a unique thunk for every invocation of the containing function, that sets up a context pointer and then calls the nested function. This ends up being a rather Icky hack, and something that some perfectly reasonable implementations can't do (for example, on a system that forbids execution of writable memory - which a lot of modern OSs do for security reasons).The only reasonable way to make it work in general is to force all function pointers to carry around a hidden context argument, and all functions to accept it (because in the general case you don't know when you call it whether it's a closure or an unclosed function). This is inappropriate to require in C for both technical and cultural reasons, so we're stuck with the option of either using explicit context pointers to fake a closure instead of nesting functions, or using a higher-level language that has the infrastructure needed to do it properly.

answeredAug 28, 2009 at 17:45
Sign up to request clarification or add additional context in comments.

4 Comments

You could just forbid taking the address of a nested function, couldn't you?
The two most common ways of implementing up-level variable access in nested functions are "static links", where each function has a pointer to the stack frame of its lexical parent, and "displays", which consist of an array of such pointers. It's basically a linked list vs. a fixed array. You don't need full-blown closures unless you want to permit an inner function to be called after its parent has exited (Pascal, for example, doesn't permit that).en.wikipedia.org/wiki/Call_stack#Lexically_nested_routines
I once worked on a project using Pascal on a Mac (probably Think Pascal) and someone did use pointers to nested functions and calling them caused a nasty crash until they stuck in a bogus extra parameter (I forget how; this had to get past type checking). I eventually worked out that a nested function includes the static link as an extra parameter.
More: they got away with this because they were not using variables accessed via the static link (global to the function, local to its parent). I tried to explain this to the lead developer and he wasn't interested: "It just works so why should I care?" The project failed. Am I surprised?
11

I'd like toquote something from the BDFL (Guido van Rossum):

This is because nested function definitions don't have access to the local variables of the surrounding block -- only to the globals of the containing module. This is done so that lookup of globals doesn't have to walk a chain of dictionaries -- asin C, there are just two nested scopes: locals and globals (and beyond this, built-ins). Therefore, nested functions have only a limited use. This was a deliberate decision, based upon experience with languages allowing arbitraries nesting such as Pascal and both Algols -- code with too many nested scopes is about as readable as code with too many GOTOs.

Emphasis is mine.

I believe he was referring to nested scope in Python (and as David points out in the comments, this was from 1993, and Python does support fully nested functions now) -- but I think the statement still applies.

The other part of it could have beenclosures.

If you have a function like this C-like code:

(*int()) foo() {    int x = 5;    int bar() {        x = x + 1;        return x;    }    return &bar;}

If you usebar in a callback of some sort, what happens with x? This is well-defined in many newer, higher-level languages, but AFAIK there's no well-defined way to track thatx in C -- doesbar return 6 every time, or do successive calls tobar return incrementing values? That could have potentially added a whole new layer of complication to C's relatively simple definition.

answeredAug 28, 2009 at 16:47
Mark Rushakoff's user avatar

9 Comments

Presumably, if you were using bar as a callback, you would be using the address of a local variable (bar) after the function containing it has returned. This, as would be true if bar were an int (say), should be undefined.
But most languages with first-order functions (Python and Lua for instance) do define this behavior in classic closure style --bar would return 5,6,7,... Nested functions almostrequire functions to be first-order values.
That's true... hmm, I hadn't considered that. But C and Python do different things when returning "local" arrays as well (or Lists, in python). C will return you a pointer to stack memory which is no longer well defined; Python will return you a whole new List. So they are different paradigms, and I'm not sure they are comparable.
@Mark No they don't - Pascal has always supported them.
I'd just like to point out that the quote in question is more than 10 years old:python.org/search/hypermail/python-1993/0343.html And Python fully supports nested functions AND nested scopes.
|
5

SeeC FAQ 20.24 andthe GCC manual for potential problems:

If you try to call the nested function through its address after the containing function has exited, all hell will break loose. If you try to call it after a containing scope level has exited, and if it refers to some of the variables that are no longer in scope, you may be lucky, but it's not wise to take the risk. If, however, the nested function does not refer to anything that has gone out of scope, you should be safe.

This is not really more severe than some other problematic parts of the C standard, so I'd say the reasons are mostly historical (C99 isn't reallythat different from K&R C feature-wise).

There are some cases where nested functions with lexical scope might be useful (consider a recursive inner function which doesn't need extra stack space for the variables in the outer scope without the need for a static variable), but hopefully you can trust the compiler to correctly inline such functions, ie a solution with a seperate function will just be more verbose.

answeredAug 28, 2009 at 17:41
Christoph's user avatar

1 Comment

Exactly recursion might be the main reason why they did not allow nested functions. Either this would mean they have to require tail recursive only (so the stack frames won't change) or they would have indeed to support something like closures.
4

Nested functions are a very delicate thing. Will you make them closures? If not, then they have no advantage to regular functions, since they can't access any local variables. If they do, then what do you do to stack-allocated variables? You have to put them somewhere else so that if you call the nested function later, the variable is still there. This means they'll take memory, so you have to allocate room for them on the heap. With no GC, this means that the programmer is now in charge of cleaning up the functions. Etc... C# does this, but they have a GC, and it's a considerably newer language than C.

answeredAug 28, 2009 at 17:48
Claudiu's user avatar

7 Comments

What is the problem with having stack-allocated variables if we make them closures?
Also, this might sound stupid, but why do you need closures with nested functions at all? Whats so special about nested functions? thanks!
@Lazer: Stack-allocated variables disappear when the function returns. If you have a closure, the function must have access to those variables even after it returns, in case it's called again. So you have to put them somewhere besides the stack. Why do you need them at all? Ask people who use JavaScript, Python, Ruby, Scheme, LISP, C#, etc. They're handy for certain things like creating event handlers. Also make your code more elegant in some cases.
@Claudiu: A lexically nested function can only be active while its parent is active. Nested functions don't require keeping local variables in memory after any function returns. (Unless a language allows saving the address of a nested function and calling it indirectly after the parent has finished, but I'd expect that to be either a fatal error or undefined behavior.)
@KeithThompson: depends on the implementation. in Python they can definitely be active past the time the parent returns. this is neither a fatal error nor undefined but rather well-defined and quite handy. i suppose you could implement them such that they don't store any memory and thus shouldn't be returned out of the parent. that would still have some use i suppose
|
3

It also wouldn't be too hard to add members functions to structs but they are not in the standard either.

Features are not added to C standard based on soley whether or not they are easy to implement. It's a combination of many other factors including the point in time in which the standard was written and what was common / practical then.

answeredAug 28, 2009 at 16:48
JaredPar's user avatar

3 Comments

Hmm ... not having received a definite "this is why" answer, perhaps you're right. I still wish there was a good reason though.
Unfortunately, the reason is probably as simple as 'not enough people cared for the feature'. The C standards process is generally one of codifying existing practice. Since few compilers have ever done this, it's never really been pushed to be in the standard. Given that it doesn't help much in C (since you don't have things like closures or nested global scoping that would make it really interesting to have nested functions), it's just never gotten in there.
The standardization had for charter to standardize existing practice. They did more than that, but adding nested functions would have been perceived as going to far. You have to go back to the 70s and the definition of C as a system language -- on par with BCPL and BLISS and assemblers.
3

One more reason: it is not at all clear that nested functions are valuable. Twenty-odd years ago I used to do large scale programming and maintenance in (VAX) Pascal. We had lots of old code that made heavy use of nested functions. At first, I thought this was way cool (compared to K&R C, which I had been working in before) and started doing it myself. After awhile, I decided it was a disaster, and stopped.

The problem was that a function could have agreat many variables in scope, counting the variables of all the functions in which it was nested. (Some old code had ten levels of nesting; five was quite common, and until I changed my mind I coded a few of the latter myself.) Variables in the nesting stack could have the same names, so that "inner" function local variables could mask variables of the same name in more "outer" functions. A local variable of a function, that in C-like languages is totally private to it, could be modified by a call to a nested function. The set of possible combinations of this jazz was near infinite, and a nightmare to comprehend when reading code.

So, I started calling this programming construct "semi-global variables" instead of "nested functions", and telling other people working on the code that the only thing worse than a global variable was a semi-global variable, and please do not create any more. I would have banned it from the language, if I could. Sadly, there was no such option for the compiler...

answeredAug 12, 2013 at 21:12
Kafka's user avatar

Comments

2

ANSI C has been established for 20 years. Perhaps between 1983 and 1989 the committee may have discussed it in the light of the state of compiler technology at the time but if they did their reasoning is lost in dim and distant past.

Steven Sudit's user avatar
Steven Sudit
19.7k1 gold badge53 silver badges54 bronze badges
answeredAug 28, 2009 at 16:32
AnthonyWJones's user avatar

4 Comments

Pretty sure you meant years there...heh.
:) yes its not the first time I've mixed decades for years, been coding for 30 years so I tend to think in terms of decades and then get them muddled, that's what Age does to you. :(
I doubt it was a state of the art problem. The problem was solved since the 60s.
I suspect it's simpler than that. The C committee is not known for making stuff up (as opposed to the C++ committee, who do design new things on a regular basis). The C committee likes to standardize stuff that people already do, and very few compilers do this. So they haven't standardized it. If it comes into more common use, they'll probably add it.
2

I disagree with Dave Vandervies.

Defining a nested function is much better coding style than defining it in global scope, making it static and adding a comment saying "This is a helper function used only by myfunc()".

What if you needed a helper function for this helper function? Would you add a comment "This is a helper function for the first helper function used only by myfunc"? Where do you take the names from needed for all those functions without polluting the namespace completely?

How confusing can code be written?

But of course, there is the problem with how to deal with closuring, i.e. returning a pointer to a function that has access to variables defined in the function from which it is returned.

answeredJan 20, 2013 at 16:53
Herr Pilsner's user avatar

Comments

0

Either you don't allow references to local variables of the containing function in the contained one, and the nesting is just a scoping feature without much use, or you do. If you do, it is not a so simple feature: you have to be able to call a nested function from another one while accessing the correct data, and you also have to take into account recursive calls. That's not impossible -- techniques are well known for that and where well mastered when C was designed (Algol 60 had already the feature). But it complicates the run-time organization and the compiler and prevent a simple mapping to assembly language (a function pointer must carry on information about that; well there are alternatives such as the one gcc use). It was out of scope for the system implementation language C was designed to be.

answeredAug 28, 2009 at 17:45
AProgrammer's user avatar

Comments

Your Answer

Sign up orlog in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

By clicking “Post Your Answer”, you agree to ourterms of service and acknowledge you have read ourprivacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.