views:

568

answers:

9

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.

thanks

+2  A: 

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.

AnthonyWJones
Pretty sure you meant years there...heh.
Kyle Walsh
...or you added an extra 0.
Kyle Walsh
Fixed. .
Steven Sudit
:) 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. :(
AnthonyWJones
I doubt it was a state of the art problem. The problem was solved since the 60s.
AProgrammer
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.
Michael Kohne
+6  A: 

I'd like to quote 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 -- as in 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 been closures.

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 use bar 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 that x in C -- does bar return 6 every time, or do successive calls to bar return incrementing values? That could have potentially added a whole new layer of complication to C's relatively simple definition.

Mark Rushakoff
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.
des4maisons
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 almost *require* functions to be first-order values.
Mark Rushakoff
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.
des4maisons
@Mark No they don't - Pascal has always supported them.
anon
@des: Python won't create a new list object, but rather it will return a reference to that local variable, which will cause that list to not be garbage collected. But you're still right to say they are different paradigms. @Neil: How does Pascal behave if you create a closure-like function such as the manner above?
Mark Rushakoff
They were in Algol 60. I don't remember if it was possible to do that in Algol 60. IIRC, in Pascal (as defined by Wirth), it wasn't possible. It was possible in Algol 68 but functions are first order in that language.
AProgrammer
@AProgrammer No, Pascal as defined by Wirth supported them - in fact they are implicit in the original Pascal programming model - everything is nested. This leads to horrible code, IMHO.
anon
I'd just like to point out that the quote in question is more than 10 years old: http://www.python.org/search/hypermail/python-1993/0343.htmlAnd Python fully supports nested functions AND nested scopes.
David Wolever
@Neil, I wasn't clear: the "that" refered to the example. IE while it was possible in Pascal to define local procedures (and even to jump out of one of those to the containing procedures, a simplified kind of stack unwinding an exception) and to have function parameters, it wasn't possible have function pointers and thus to return a local function from another one or to store a local function pointer in a global variable. So the need for full closure (as opposed to upward closure needed for functions parameters) was absent.
AProgrammer
+3  A: 

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.

JaredPar
Hmm ... not having received a definite "this is why" answer, perhaps you're right. I still wish there was a good reason though.
des4maisons
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.
Michael Kohne
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.
AProgrammer
A: 

Basically, because they are not needed. What kind of programs would nested functions allow to be written that C does not currently allow?

anon
They are never _needed_, but they sure as heck are useful :) Consider a very specific routine that is called multiple times within only one function. Or suppose you wanted to pass an on-the-fly function as an argument. Sure, you could have separate definitions outside the scope of the parent function, but that would neither illustrate that those definitions only exist because of that parent, nor would it keep your namespace clear.
des4maisons
Your first problem can be solved with a comment, and the second with a suitable name and the use of static. But I find it very rare that a function is only called from one other function.
anon
Like I said, it's never needed. Local functions (and lambdas, and all that other magic) are heavily in Scheme, and for a good reason. Also, with static, even though the namespacing issue is much reduced, you still are using up names in that module's space.
des4maisons
I think the issue is that for C programs, you generally don't have enough stuff in a given module's static namespace that you're going to care about a few extra names. It would be nice for scoping purposes, but it would also make the source code much more annoying to read.
Michael Kohne
Scheme is functional. It's designed around functions, so of course you'll need nested ones. It also is GC'ed, which works better for these kind of things. I think Neil is arguing that in C-style code, you can do things another way.
Claudiu
There are **very few things that are actually needed**. Classes are not needed; you can code without. Functions are not needed, you can do it with gotos. Same for ifs, whiles, fors, etc. And yet we have them, because they make our lives easier; for the very same reason nested functions would be useful.
Andreas Bonini
@andreas Are you going through my low-scoring posts downvoting them? If so, I may have to complain about you.
anon
@Neil: I'm going through your low scoring posts and voting them where I see fit, I see nothing wrong with that. It's nothing personal and not a personal attack, I voted other posts on those pages and it's just a way for me to kill the time; I have nothing against you personally. I'm pretty sure I also upvoted one of your posts, and I most likely downvoted less than 5, so you even gained rep because of this. It's a way for me to browse random questions like any other.
Andreas Bonini
@Andreas If there is "nothing personal" in your actions, why are you going through *my* posts specifically? Also, you do know that such actions will probably be seen by the SO admin scripts as tactical downvoting, and cancelled?
anon
@Neil: then wait for the script to kick in, I don't know what to tell you. If I see a bad post I downvote it, and like I said it's just a way for me to browse random stuff. And I go through the posts of many high profile SO users, I've done the same with jon skeet, jeff atwood and others, and you're the first to complain for a couple of downvotes.. I've went through my recent page, I downvoted 5 of your posts and upvoted one. Net: 0 rep. They were bad posts, and I don't like when people make it a huge deal when I downvote them, so please don't.
Andreas Bonini
@andreas Strange that you chose to "randomly" only look at my low-scoring answers. And imagine how much I care about your likes or dislikes.
anon
+4  A: 

See C FAQ 20.24 and the 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 really that 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.

Christoph
A: 

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.

AProgrammer
+7  A: 

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.

lol @ your first 2 paragraphs - they're the same as mine
Claudiu
You could just forbid taking the address of a nested function, couldn't you?
caf
+3  A: 

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.

Claudiu
@Claudiu: What is the problem with having stack-allocated variables if we make them closures?
Lazer
@Claudiu: Also, this might sound stupid, but why do you need closures with nested functions at all? Whats so special about nested functions? thanks!
Lazer
@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
@Claudiu: thanks! I understand now.
Lazer
A: 

Your question and it's answer form a tautology... Why? Because!

I might as well ask why C does not have, oh I dunno, pass by reference instead of pass by value as default. Or anything else that it does not have.

If you want nested functions, good on ya! Find and use a language that supports them.

Eric M