83

This is not a lambda function question, I know that I can assign a lambda to a variable.

What's the point of allowing us to declare, but not define a function inside code?

For example:

#include <iostream>

int main()
{
    // This is illegal
    // int one(int bar) { return 13 + bar; }

    // This is legal, but why would I want this?
    int two(int bar);

    // This gets the job done but man it's complicated
    class three{
        int m_iBar;
    public:
        three(int bar):m_iBar(13 + bar){}
        operator int(){return m_iBar;}
    }; 

    std::cout << three(42) << '\n';
    return 0;
}

So what I want to know is why would C++ allow two which seems useless, and three which seems far more complicated, but disallow one?

EDIT:

From the answers it seems that there in-code declaration may be able to prevent namespace pollution, what I was hoping to hear though is why the ability to declare functions has been allowed but the ability to define functions has been disallowed.

David Hammen
  • 32,454
  • 9
  • 60
  • 108
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • 3
    The first, `one` is a function *definition*, the other two are *declarations*. – Some programmer dude Apr 30 '15 at 12:02
  • 9
    I think you got the terms the wrong way -- you want to ask "What's the point of allowing us to *declare, but not define* a function inside code?". And while we are at it, you probably mean "inside a *function*". It's all "code". – Peter - Reinstate Monica Apr 30 '15 at 12:02
  • 14
    If you're asking why the language has quirks and inconsistencies: because it evolved over several decades, through the work of many people with many different ideas, from languages invented for different reasons at different times. If you're asking why it has this particular quirk: because no-one (so far) thought local function definitions were useful enough to standardise. – Mike Seymour Apr 30 '15 at 12:04
  • 4
    @MikeSeymour has it properly right. C is not as well structured as, say, Pascal, and always allowed only top-level function definitions. So the reason is historic, plus a lacking need to change it. That function *declarations* are possible is just a consequence of scoped declarations in general being possible. Prohibiting that for functions would have meant an extra rule. – Peter - Reinstate Monica Apr 30 '15 at 12:09
  • @MikeSeymour Sounds like the best answer so far. But I still don't get why they allowed function declaration in the code though. – Jonathan Mee Apr 30 '15 at 12:09
  • 3
    @JonathanMee: Probably because, in general, declarations are allowed in blocks, and there's no particular reason to specifically forbid function declarations; it's simpler to just allow any declaration with no special cases. But "why" isn't really an answerable question; the language is what it is because that's how it evolved. – Mike Seymour Apr 30 '15 at 12:12
  • 2
    In practice you would not use `class three`, you'd use a lambda ... that's why they were added, to reduce exactly this verbiage. Also this question has nothing at all to do with MVP. – M.M Apr 30 '15 at 12:17
  • @MattMcNabb I agree that I'd use a lambda, I was thinking there was some deeper mechanism of the language that I was missing. Isn't Most Vexing Parse where a the programmer thinks he is constructing a variable and accidentally declares a function? Seems related to me? – Jonathan Mee Apr 30 '15 at 12:42
  • possible duplicate of [Is there a use for function declarations inside functions?](http://stackoverflow.com/questions/6089452/is-there-a-use-for-function-declarations-inside-functions) – pdeschain Apr 30 '15 at 12:43
  • [There are ADL cases where this matters](http://stackoverflow.com/a/25976453/1708801) ... see the example at the end of my answer. – Shafik Yaghmour Apr 30 '15 at 12:58
  • @ShafikYaghmour I read through your answer, and learned a little something about ADL, but I can't see how this pertains. – Jonathan Mee Apr 30 '15 at 13:10
  • 1
    @JonathanMee well it an example that covers your comment `This is legal, but why would I want this` – Shafik Yaghmour Apr 30 '15 at 13:46
  • 3
    Defining function was [proposed a long time ago](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/1993/N0295.pdf) but since we don't have mintues for that meeting we don't know why it was rejected. – Shafik Yaghmour Apr 30 '15 at 13:48
  • 1
    @ShafikYaghmour That would make a pretty great answer. – Jonathan Mee Apr 30 '15 at 13:57
  • Aside: The sample code does not invoke the most vexing parse. Please do not add that tag back in. – David Hammen Apr 30 '15 at 21:10
  • Regarding `int two(int)` -- there are multiple reasons why this is allowed. One is that it makes parsing easier (Jerry Coffin's answer). Another is that because it is allowed, there's lots of legacy code (and even some modern code) that uses such constructs. A very compelling case needs to be made for a proposed change that revokes backwards compatibility. – David Hammen Apr 30 '15 at 21:45
  • Regarding `three(42)` -- This is not the most vexing parse. `three(42)` creates an instance of `class three`. There is no stream insertion operator for this class (e.g., `std::ostream& operator<<(std::ostream&, const three&)`), so the compiler looks for a conversion operator that will convert an object of type `three` to a type for which a stream insertion operator does exist. That of course `three::operator int()`. – David Hammen Apr 30 '15 at 21:56
  • 1
    Actually, nested functions are available as a GNU extension in gcc. This has nothing to do with why standard C/C++ allow you to declare functions inside function definitions, but is worth mentioning. See https://gcc.gnu.org/onlinedocs/gcc/Nested-Functions.html – Artelius Apr 30 '15 at 22:54
  • @Artelius note that the document says `but are not supported by GNU C++. `. – Shafik Yaghmour May 01 '15 at 09:19
  • @DavidHammen Most Vexing Parse(MVP) is hat annoys me about this, that was edited out of an early version of the question (not by me.) Part of my question was why allow in code function defines *at all* if all they do is incite MVP and you can't define them anyway. After understanding some of the answers here I understand *why* we need in code definitions, however it perplexes me why no one sees that this has to do with MVP. – Jonathan Mee May 01 '15 at 11:28
  • @JonathanMee - In the original version of the question, you didn't use that wording. What you wrote about most vexing parse instead looked out of place. What you apparently want is for `int f();` to be a function declaration when used at namespace scope but a variable declaration when used at function scope. That's a bit scary. – David Hammen May 01 '15 at 12:28
  • @JonathanMee - Regarding `int two(int bar);` you asked "This is legal, but why would I want this?" In modern code, you don't want to do this. The problem is that not all code compiled by the compiler is modern code. There's lots and lots of old code out there that does exactly this. In the early days of C, some even advocated that this was the "right way" to declare functions as it lets readers of the code see a function's fanout right up front. Some of that code still exists. And it still compiles, as-is. – David Hammen May 01 '15 at 12:31
  • 1
    I didn't see it mentioned, but there's a much easier way of using the `class` approach, `struct {int operator()(int i) {return i;}} func; func(42);`, see: https://ideone.com/0j8kTK – cartographer May 01 '15 at 16:37
  • @cartographer Yeah you are correct; I realized that after I wrote it, but decided against modifying the question cause this really isn't about how to more effectively write an in code class, it's about why can't I define a function in code when I can declare a function in code. – Jonathan Mee May 01 '15 at 17:20
  • @DavidHammen The question is a simplified version of what is linked. What I wanted to know is, why do I have to put up with the aggravation of MVP and I can't get the benefits of in code function definition. I think my question has been answered, so I'm not going to continue to go back and forth with people editing this. But I feel sad that it had to be defaced by people who thought they understood my question better than I did :( – Jonathan Mee May 01 '15 at 23:56
  • @JonathanMee - You have to put up with it because people wrote code that used this exact construct 30 or even 40 years ago. That code still compiles, sometimes with a lot of warnings, but it still compiles. There's a lot to be said against backwards compatibility, but there's a lot more to be said for it. Money talks. Having to rewrite that legacy code would cost lots and lots and lots of money. It would cost enough money to justify a campaign to fire every member of the C++ standards committee who approved of your desired change fired -- and then the standard would be reverted. – David Hammen May 02 '15 at 00:09
  • @DavidHammen Yeah, I didn't understand the usefulness of it until I read some of the comments. As you said this was even advocated by some as the "right way" to limit scope. Welp, that's why I ask questions on here to learn stuff. There's an awful lot of knowledge in some of these answers, and for that I'm very grateful. – Jonathan Mee May 02 '15 at 00:15
  • Nowadays, those old ideas of how to limit scope are viewed as old ideas. When you asked "why would I want to do this", the answer is you don't. Those are ideas from a previous millennium. We humans try lots of ideas. Some turn out to be fantastic, others OK, yet others, blech! If we only could know ahead of time which was which ... – David Hammen May 02 '15 at 00:22

11 Answers11

42

It is not obvious why one is not allowed; nested functions were proposed a long time ago in N0295 which says:

We discuss the introduction of nested functions into C++. Nested functions are well understood and their introduction requires little effort from either compiler vendors, programmers, or the committee. Nested functions offer significant advantages, [...]

Obviously this proposal was rejected, but since we don't have meeting minutes available online for 1993 we don't have a possible source for the rationale for this rejection.

In fact this proposal is noted in Lambda expressions and closures for C ++ as a possible alternative:

One article [Bre88] and proposal N0295 to the C ++ committee [SH93] suggest adding nested functions to C ++ . Nested functions are similar to lambda expressions, but are defined as statements within a function body, and the resulting closure cannot be used unless that function is active. These proposals also do not include adding a new type for each lambda expression, but instead implementing them more like normal functions, including allowing a special kind of function pointer to refer to them. Both of these proposals predate the addition of templates to C ++ , and so do not mention the use of nested functions in combination with generic algorithms. Also, these proposals have no way to copy local variables into a closure, and so the nested functions they produce are completely unusable outside their enclosing function

Considering we do now have lambdas we are unlikely to see nested functions since, as the paper outlines, they are alternatives for the same problem and nested functions have several limitations relative to lambdas.

As for this part of your question:

// This is legal, but why would I want this?
int two(int bar);

There are cases where this would be a useful way to call the function you want. The draft C++ standard section 3.4.1 [basic.lookup.unqual] gives us one interesting example:

namespace NS {
    class T { };
    void f(T);
    void g(T, int);
}

NS::T parm;
void g(NS::T, float);

int main() {
    f(parm); // OK: calls NS::f
    extern void g(NS::T, float);
    g(parm, 1); // OK: calls g(NS::T, float)
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • 1
    Question wrt the 3.4.1 example you give: Couldn't the caller in main simply write `::g(parm, 1)` in order to call the function in the global namespace? Or call `g(parm, 1.0f);` which should result in a better match for the desired `g`? – Peter - Reinstate Monica Apr 30 '15 at 15:24
  • @PeterSchneider I made too strong a statement there, I adjusted it. – Shafik Yaghmour Apr 30 '15 at 17:40
  • 1
    I'd like to add the comment here: This answer was accepted not because it did the best job of explaining why in code function declarations are allowed; but because it did the best job describing why in code function definitions are not allowed, which was the actual question. And specifically it specifically outlines why the hypothetical implementation of in code functions would differ from the implementation of lambdas. +1 – Jonathan Mee May 01 '15 at 19:14
  • 1
    @JonathanMee: How in the world does: "...we don't have a possible source for the rationale for this rejection." qualify as the best job of describing why nested function definitions aren't allowed (or even attempting to describe it at all?) – Jerry Coffin May 06 '15 at 09:34
  • @JerryCoffin The answer included the official rationale of why lambdas are already a super set of in code function definitions rendering their implementation unnecessary: "The resulting closure cannot be used unless that function is active... Also, these proposals have no way to copy local variables into a closure." I assume that you're asking why your analysis of the additional complexity placed upon compilers was not the answer I accepted. If so: You speak to the difficulty of something lambdas already accomplish, in code definitions could clearly be implemented exactly like lambdas. – Jonathan Mee May 06 '15 at 11:30
  • @JonathanMee: The decision(s) to reject nested functions happened decades before lambdas were added in C++11 so explanations based on lambda expressions make no sense at all. Don't get me wrong: I'm not trying to tell you to accept a different answer. I'm primarily interested in seeing how I could improve future posts, and in this case the suggestion seems to be: "write posts that don't even make sense." – Jerry Coffin May 06 '15 at 14:19
  • @JerryCoffin Let me just summarize my understanding of this answer: "In code function definitions were revisited in the development of the C++11 feature set, but they were rejected as a subset of lambda functionality." My understanding of your post: "In code function definition was rejected historically because of implementation complexity. Currently in code function definitions are available in gcc, or in standardized lambdas." These answers seem similar when I summarize them, but the clear-cut quote from the standard committee in this answer was what sold me. – Jonathan Mee May 06 '15 at 14:29
  • @JonathanMee: This seems to be completely mistaken. I'm quite certain nobody revisited the idea of adding nested functions when developing the C++11 feature set. The reasoning there was being used as justification for lambdas. In essence: "for years, a few people have wanted to added nested functions, and with lambdas, we get/provide a superset of that capability." – Jerry Coffin May 06 '15 at 14:35
  • @JerryCoffin Your summary: "For years, a few people have wanted to added nested functions, and with lambdas, we get/provide a superset of that capability." In coloration with the this answer's statement that the standards committee had previously rejected in code function definitions, makes what I would consider a well sourced answer to my question, why has, "The ability to declare functions has been allowed but the ability to define functions has been disallowed?" – Jonathan Mee May 06 '15 at 14:50
31

Well, the answer is "historical reasons". In C you could have function declarations at block scope, and the C++ designers did not see the benefit in removing that option.

An example usage would be:

#include <iostream>

int main()
{
    int func();
    func();
}

int func()
{
    std::cout << "Hello\n";
}

IMO this is a bad idea because it is easy to make a mistake by providing a declaration that does not match the function's real definition, leading to undefined behaviour which will not be diagnosed by the compiler.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • 10
    "This is generally considered a bad idea' - citation required. – Richard Hodges Apr 30 '15 at 12:20
  • 4
    @RichardHodges: Well, function declarations belong in header files, and the implementation in .c or .cpp files, so having these declarations inside function definitions violates either of those two guidelines. – MSalters Apr 30 '15 at 12:26
  • header files are certainly convenient places to put function declarations but there is no language rule that stipulates that this must be the case. If you only want access to one name from another compilation unit, there's no need to import all the names exported from that compilation unit. – Richard Hodges Apr 30 '15 at 12:29
  • @RichardHodges: "there is no language rule" - but there is one that stipulates that declarations must match the corresponding definition, and doing this prevents the compiler from enforcing that rule (if the definition is in a different translation unit). Which makes it a bad idea. – Mike Seymour Apr 30 '15 at 12:35
  • 2
    How does it prevent the declaration being different to the definition? – Richard Hodges Apr 30 '15 at 12:37
  • @RichardHodges: With just one declaration in a header, you can include it in the translation unit that defines the function, allowing the compiler to check that the definition matches the declaration. Declaring it in other places prevents that check, potentially leading to undefined behaviour if you get a declaration wrong. So that's a bad idea. – Mike Seymour Apr 30 '15 at 12:45
  • @MikeSeymour Can you explain in a bit more detail, I'm having trouble keeping up. What I understood this to say is, an in code declaration of a previously declared function prevents the compiler from checking both declarations. Is that what you are saying? – Jonathan Mee Apr 30 '15 at 12:56
  • This is legal code. It declares 2 functions and defines one. C++ is not the same as C. `int foo(); int foo(int); int foo(int) { return 0; }` – Richard Hodges Apr 30 '15 at 12:58
  • 1
    @JonathanMee: I'm saying that, if the declaration you're using isn't available where the function is defined, the compiler might not be checking that the declaration matches the definition. So you might have a local declaration `some_type f();`, and a definition in another translation unit `another_type f() {...}`. The compiler can't tell you that these don't match, and calling `f` with the wrong declaration will give undefined behaviour. So it's a good idea to only have one declaration, in a header, and include that header where the function is defined, as well as where it's used. – Mike Seymour Apr 30 '15 at 13:00
  • @RichardHodges: But you could declare `int foo()` in one place, and define `void foo()` elsewhere. That's illegal, but the compiler won't help you if it can't see both. You'll get nasty undefined behaviour, not a friendly compile error. – Mike Seymour Apr 30 '15 at 13:01
  • 6
    I think what you're saying is that the common practice of putting function declarations in header files is generally useful. I don't think anyone would disagree with that. What I see no reason for is the assertion that declaring an external function at function scope is 'generally considered a bad idea'. – Richard Hodges Apr 30 '15 at 13:04
  • @RichardHodges: To repeat myself yet again: if the function is defined in a different translation unit then it's a bad idea because, without a declaration in a header, the compiler can't check that the declaration matches the definition. (With a declaration in a header, or the function defined in the same unit, a duplicate declaration is pointless, so still a somewhat bad idea.) – Mike Seymour Apr 30 '15 at 13:07
  • @RichardHodges re-worded – M.M Apr 30 '15 at 13:09
  • 1
    The error you foresee would be caught at link time because the two functions would have different names (the return type is part of the name). The use-case of the local declaration is when you want one or two functions from a library without taking them all. In the old days this could help a compiler to not run out of memory (yup!!). These days it's less useful I'll grant you. But the 'bad idea' bit is opinion, not fact. – Richard Hodges Apr 30 '15 at 13:16
  • @RichardHodges: There's no guarantee that the return type forms part of the mangled name, since it isn't part of the signature. At least one popular mangling scheme (used by GCC) doesn't include the return type, so the error won't be caught by the linker, and will give undefined behaviour. So it's a bad idea. – Mike Seymour Apr 30 '15 at 13:19
  • 1
    This answer would be better without the editorial comment. IMO, disallowing it would be far worse than the current situation for the simple reason that disallowing it would mean a lot of legacy code that no longer compiles. Moreover, disallowing this won't fix the problem. What fixes the problem is disallowing declarations of functions with external linkage in source files. That's the job of a coding standard, not the language specification. – David Hammen Apr 30 '15 at 22:12
  • @DavidHammen I meant, apart from that issue. Have removed the comment in any case. – M.M May 01 '15 at 21:35
  • 1
    @MattMcNabb - With that, +1. (Note: I did not downvote prior to this. It was just a little editorial.) Apart from that issue, yes, do not do this in modern code. It would be nice to have a compiler warning along the lines of `-Warchaic-legacy-nonsense` (and maybe have it on by default). With that, `int f() { int g(); return g();}` would still compile; it would just get a warning. – David Hammen May 01 '15 at 21:44
23

In the example you give, void two(int) is being declared as an external function, with that declaration only being valid within the scope of the main function.

That's reasonable if you only wish to make the name two available within main() so as to avoid polluting the global namespace within the current compilation unit.

Example in response to comments:

main.cpp:

int main() {
  int foo();
  return foo();
}

foo.cpp:

int foo() {
  return 0;
}

no need for header files. compile and link with

c++ main.cpp foo.cpp 

it'll compile and run, and the program will return 0 as expected.

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • Wouldn't `two` also have to be defined in the file thereby causing the pollution anyway? – Jonathan Mee Apr 30 '15 at 12:51
  • 1
    @JonathanMee no, `two()` could be defined in an entirely different compilation unit. – Richard Hodges Apr 30 '15 at 13:19
  • I need help understanding how that would work. Wouldn't you have to include the header it was declared in? At which point it would be declared, right? I just don't see how you can define it in code, and somehow not include the file that declares it? – Jonathan Mee Apr 30 '15 at 13:23
  • 5
    @JonathanMee There's nothing special about headers. They're just a convenient place to put declarations. A declaration within a function is just as valid as a declaration within a header. So, no, you wouldn't need to include the header of what you're linking to (there may not even be a header at all). – Cubic Apr 30 '15 at 14:11
  • @Cubic So you're saying that I could have an in code definition of `int foo(int)` in file X.h and the implementation of `int foo(int)` in X.cpp? I guess that makes sense. – Jonathan Mee Apr 30 '15 at 14:16
  • 1
    @JonathanMee In C/C++ lingo, definition and implementation are the same thing. You can declare a function as often as you want, but you can only define it once. The declaration doesn't need to be in a file ending in .h - you can have a file use.cpp that has a function bar that calls foo (declaring foo in its body), and a file provides.cpp that defines foo, and it'd work fine as long as you don't mess up the linking step. – Cubic Apr 30 '15 at 14:23
19

You can do these things, largely because they're actually not all that difficult to do.

From the viewpoint of the compiler, having a function declaration inside another function is pretty trivial to implement. The compiler needs a mechanism to allow declarations inside of functions to handle other declarations (e.g., int x;) inside a function anyway.

It will typically have a general mechanism for parsing a declaration. For the guy writing the compiler, it doesn't really matter at all whether that mechanism is invoked when parsing code inside or outside of another function--it's just a declaration, so when it sees enough to know that what's there is a declaration, it invokes the part of the compiler that deals with declarations.

In fact, prohibiting these particular declarations inside a function would probably add extra complexity, because the compiler would then need an entirely gratuitous check to see if it's already looking at code inside a function definition and based on that decide whether to allow or prohibit this particular declaration.

That leaves the question of how a nested function is different. A nested function is different because of how it affects code generation. In languages that allow nested functions (e.g., Pascal) you normally expect that the code in the nested function has direct access to the variables of the function in which it's nested. For example:

int foo() { 
    int x;

    int bar() { 
        x = 1; // Should assign to the `x` defined in `foo`.
    }
}

Without local functions, the code to access local variables is fairly simple. In a typical implementation, when execution enters the function, some block of space for local variables is allocated on the stack. All the local variables are allocated in that single block, and each variable is treated as simply an offset from the beginning (or end) of the block. For example, let's consider a function something like this:

int f() { 
   int x;
   int y;
   x = 1;
   y = x;
   return y;
}

A compiler (assuming it didn't optimize away the extra code) might generate code for this roughly equivalent to this:

stack_pointer -= 2 * sizeof(int);      // allocate space for local variables
x_offset = 0;
y_offset = sizeof(int);

stack_pointer[x_offset] = 1;                           // x = 1;
stack_pointer[y_offset] = stack_pointer[x_offset];     // y = x;
return_location = stack_pointer[y_offset];             // return y;
stack_pointer += 2 * sizeof(int);

In particular, it has one location pointing to the beginning of the block of local variables, and all access to the local variables is as offsets from that location.

With nested functions, that's no longer the case--instead, a function has access not only to its own local variables, but to the variables local to all the functions in which it's nested. Instead of just having one "stack_pointer" from which it computes an offset, it needs to walk back up the stack to find the stack_pointers local to the functions in which it's nested.

Now, in a trivial case that's not all that terrible either--if bar is nested inside of foo, then bar can just look up the stack at the previous stack pointer to access foo's variables. Right?

Wrong! Well, there are cases where this can be true, but it's not necessarily the case. In particular, bar could be recursive, in which case a given invocation of bar might have to look some nearly arbitrary number of levels back up the stack to find the variables of the surrounding function. Generally speaking, you need to do one of two things: either you put some extra data on the stack, so it can search back up the stack at run-time to find its surrounding function's stack frame, or else you effectively pass a pointer to the surrounding function's stack frame as a hidden parameter to the nested function. Oh, but there's not necessarily just one surrounding function either--if you can nest functions, you can probably nest them (more or less) arbitrarily deep, so you need to be ready to pass an arbitrary number of hidden parameters. That means you typically end up with something like a linked list of stack frames to surrounding functions, and access to variables of surrounding functions is done by walking that linked list to find its stack pointer, then accessing an offset from that stack pointer.

That, however, means that access to a "local" variable may not be a trivial matter. Finding the correct stack frame to access the variable can be non-trivial, so access to variables of surrounding functions is also (at least usually) slower than access to truly local variables. And, of course, the compiler has to generate code to find the right stack frames, access variables via any of an arbitrary number of stack frames, and so on.

This is the complexity that C was avoiding by prohibiting nested functions. Now, it's certainly true that a current C++ compiler is a rather different sort of beast from a 1970's vintage C compiler. With things like multiple, virtual inheritance, a C++ compiler has to deal with things on this same general nature in any case (i.e., finding the location of a base-class variable in such cases can be non-trivial as well). On a percentage basis, supporting nested functions wouldn't add much complexity to a current C++ compiler (and some, such as gcc, already support them).

At the same time, it rarely adds much utility either. In particular, if you want to define something that acts like a function inside of a function, you can use a lambda expression. What this actually creates is an object (i.e., an instance of some class) that overloads the function call operator (operator()) but it still gives function-like capabilities. It makes capturing (or not) data from the surrounding context more explicit though, which allows it to use existing mechanisms rather than inventing a whole new mechanism and set of rules for its use.

Bottom line: even though it might initially seem like nested declarations are hard and nested functions are trivial, more or less the opposite is true: nested functions are actually much more complex to support than nested declarations.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
5

The first one is a function definition, and it is not allowed. Obvious, wt is the usage of putting a definition of a function inside another function.

But the other twos are just declarations. Imagine you need to use int two(int bar); function inside the main method. But it is defined below the main() function, so that function declaration inside the function makes you to use that function with declarations.

The same applies to the third. Class declarations inside the function allows you to use a class inside the function without providing an appropriate header or reference.

int main()
{
    // This is legal, but why would I want this?
    int two(int bar);

    //Call two
    int x = two(7);

    class three {
        int m_iBar;
        public:
            three(int bar):m_iBar(13 + bar) {}
            operator int() {return m_iBar;}
    };

    //Use class
    three *threeObj = new three();

    return 0;
}
Smart Manoj
  • 5,230
  • 4
  • 34
  • 59
ANjaNA
  • 1,404
  • 2
  • 16
  • 29
4

This language feature was inherited from C, where it served some purpose in C's early days (function declaration scoping maybe?). I don't know if this feature is used much by modern C programmers and I sincerely doubt it.

So, to sum up the answer:

there is no purpose for this feature in modern C++ (that I know of, at least), it is here because of C++-to-C backward compatibility (I suppose :) ).


Thanks to the comment below:

Function prototype is scoped to the function it is declared in, so one can have a tidier global namespace - by referring to external functions/symbols without #include.

pdeschain
  • 1,411
  • 12
  • 21
  • the purpose is controlling the scope of the name to avoid global namespace pollution. – Richard Hodges Apr 30 '15 at 12:19
  • Ok, I suppose it is useful for situations, when you want to refer to external functions/symbols without polluting the global namespace with #include! Thanks for pointing it out. I'll make an edit. – pdeschain Apr 30 '15 at 12:39
4

Actually, there is one use case which is conceivably useful. If you want to make sure that a certain function is called (and your code compiles), no matter what the surrounding code declares, you can open your own block and declare the function prototype in it. (The inspiration is originally from Johannes Schaub, https://stackoverflow.com/a/929902/3150802, via TeKa, https://stackoverflow.com/a/8821992/3150802).

This may be particularily useful if you have to include headers which you don't control, or if you have a multi-line macro which may be used in unknown code.

The key is that a local declaration supersedes previous declarations in the innermost enclosing block. While that can introduce subtle bugs (and, I think, is forbidden in C#), it can be used consciously. Consider:

// somebody's header
void f();

// your code
{   int i;
    int f(); // your different f()!
    i = f();
    // ...
}

Linking may be interesting because chances are the headers belong to a library, but I guess you can adjust the linker arguments so that f() is resolved to your function by the time that library is considered. Or you tell it to ignore duplicate symbols. Or you don't link against the library.

Community
  • 1
  • 1
Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
  • So help me out here, where would `f` get defined in your example? Would I not end up with a function redefinition error since these differ only by return type? – Jonathan Mee Apr 30 '15 at 12:48
  • @JonathanMee hmmm... f() could be defined in a different translation unit, I thought. But probably the linker would balk if you also linked against the assumed library, I assume, you are right. So you cannot do that ;-), or at least have to ignore multiple definitions. – Peter - Reinstate Monica Apr 30 '15 at 12:50
  • Bad example. There is no distinction between `void f()` and `int f()` in C++ because a function's return value is not part of the function's signature in C++. Change the second declaration to `int f(int)` and I'll remove my downvote. – David Hammen Apr 30 '15 at 14:56
  • @DavidHammen Try to compile `i = f();` after declaring `void f()`. "No distinction" is only half the truth ;-). I actually used non-overloadable function "signatures" because otherwise the whole circumstance would be unnecessary in C++ because two functions with different parameter types/numbers could happily coexist. – Peter - Reinstate Monica Apr 30 '15 at 14:59
  • @DavidHammen Indeed, after reading Shafik's answer I believe we have three cases: **1. Signature differs in parameters.** No issue in C++, simple overload and best match rules work. **2. Signature does not differ at all.** No issue at language level; function is resolved by linking against the desired implementation. **3. Difference is only in return type.** There *is* an issue at the language level, as demonstrated; overload resolution doesn't work; we have to declare a function with a different signature *and* link appropriately. – Peter - Reinstate Monica Apr 30 '15 at 18:05
3

This is not an answer to the OP question, but rather a reply to several comments.

I disagree with these points in the comments and answers: 1 that nested declarations are allegedly harmless, and 2 that nested definitions are useless.

1 The prime counterexample for the alleged harmlessness of nested function declarations is the infamous Most Vexing Parse. IMO the spread of confusion caused by it is enough to warrant an extra rule forbidding nested declarations.

2 The 1st counterexample to the alleged uselessness of nested function definitions is frequent need to perform the same operation in several places inside exactly one function. There is an obvious workaround for this:

private:
inline void bar(int abc)
{
    // Do the repeating operation
}

public: 
void foo()
{
    int a, b, c;
    bar(a);
    bar(b);
    bar(c);
}

However, this solution often enough contaminates the class definition with numerous private functions, each of which is used in exactly one caller. A nested function declaration would be much cleaner.

Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
Michael
  • 5,775
  • 2
  • 34
  • 53
  • 1
    I think this makes a good summary of the motivation of my question. If you look at the original version I cited MVP, but I keep getting overruled in the comments (of my own question) being told that MVP is irrelevant :( I just can't figure out how the potentially harmful in code declarations are still here, but the potentially useful in code definitions are not. I've given you a +1 for the beneficial examples. – Jonathan Mee May 01 '15 at 23:44
2

Specifically answering this question:

From the answers it seems that there in-code declaration may be able to prevent namespace pollution, what I was hoping to hear though is why the ability to declare functions has been allowed but the ability to define functions has been disallowed.

Because consider this code:

int main()
{
  int foo() {

    // Do something
    return 0;
  }
  return 0;
}

Questions for language designers:

  1. Should foo() be available to other functions?
  2. If so, what should be its name? int main(void)::foo()?
  3. (Note that 2 would not be possible in C, the originator of C++)
  4. If we want a local function, we already have a way - make it a static member of a locally-defined class. So should we add another syntactic method of achieving the same result? Why do that? Wouldn't it increase the maintenance burden of C++ compiler developers?
  5. And so on...
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
  • Obviously this behavior is defined for lambdas? Why not functions defined in code? – Jonathan Mee Apr 30 '15 at 13:13
  • A lambda is merely shorthand for writing a function object. The special case of a lambda that captures no arguments is equivalent to a local function definition, as is writing a function object that has no data members. – Richard Hodges Apr 30 '15 at 14:13
  • I was just pointing out that lambdas, *and* in code declared functions already dismiss all your points. It should be no increase in "burden". – Jonathan Mee Apr 30 '15 at 14:20
  • @JonathanMee if you feel strongly about it, by all means submit an RFC to the c++ standards committee. – Richard Hodges Apr 30 '15 at 14:42
  • [Shafik Yaghmour's Answer](http://stackoverflow.com/a/29970476/2642059) covered that already being done. I personally would like to see the removal of the ability to declare functions in code if they won't let us define them. [Richard Hodges's answer](http://stackoverflow.com/a/29967592/2642059) does a good job of explaining why we still need the ability to declare in code declaration though. – Jonathan Mee Apr 30 '15 at 15:09
1

Just wanted to point out that the GCC compiler allows you to declare functions inside functions. Read more about it here. Also with the introduction of lambdas to C++, this question is a bit obsolete now.


The ability to declare function headers inside other functions, I found useful in the following case:

void do_something(int&);

int main() {
    int my_number = 10 * 10 * 10;
    do_something(my_number);

    return 0;
}

void do_something(int& num) {
    void do_something_helper(int&); // declare helper here
    do_something_helper(num);

    // Do something else
}

void do_something_helper(int& num) {
    num += std::abs(num - 1337);
}

What do we have here? Basically, you have a function that is supposed to be called from main, so what you do is that you forward declare it like normal. But then you realize, this function also needs another function to help it with what it's doing. So rather than declaring that helper function above main, you declare it inside the function that needs it and then it can be called from that function and that function only.

My point is, declaring function headers inside functions can be an indirect method of function encapsulation, which allows a function to hide some parts of what it's doing by delegating to some other function that only it is aware of, almost giving an illusion of a nested function.

Community
  • 1
  • 1
smac89
  • 39,374
  • 15
  • 132
  • 179
  • I understood that we could define a lambda inline. I understood that we could declare a function inline, but that's the origin of the [most vexing parse](https://en.wikipedia.org/wiki/Most_vexing_parse), so my question was if the standard is going to keep functionality that serves only to induce rage in programmers, shouldn't programmers be able to define the function inline too? [Richard Hodges' answer](http://stackoverflow.com/a/29967592/2642059) helped me understand the origin of this problem. – Jonathan Mee Apr 20 '16 at 11:00
0

Nested function declarations are allowed probably for 1. Forward references 2. To be able to declare a pointer to function(s) and pass around other function(s) in a limited scope.

Nested function definitions are not allowed probably due to issues like 1. Optimization 2. Recursion (enclosing and nested defined function(s)) 3. Re-entrancy 4. Concurrency and other multithread access issues.

From my limited understanding :)

NeutronStar
  • 220
  • 1
  • 4
  • 17