1. Properly encapsulating their scope, as opposed to having static functions sit awkwardly somewhere else.
2. Factoring out common code within the function.
3. A lot of my need for goto statements vanished with nested functions.
4. Take the address of a nested function, and it serves as a lambda.
5. No need to create "Context" structs to pass local data to them.
6. They replace a lot of what C macros did.
7. They're inlineable, so are not costly.
I use them more and more as time goes by. It's a pity C doesn't have them, they'd fit nicely into the language.
I think I misliked Pascal's nested procedures because they weren't true lambdas; once the outer procedure returned, the inner procs were no longer callable (just one contiguous stack, right?). Early-on, using C++ lambdas, I found myself making the same mistake in a design for some asynchronous completion stuff. Embarrassing; C++ and Pascal are not JavaScript/Lisp/Scheme/Smalltalk :-)
It's funny in this way how c++ lambdas lead to very c++ specific issues and uniquely c++-ish solutions. I think the wackiness of the closure capture mechanism is the best example of this I can think of.
int f()
{
struct local {
static int nested_func()
{
return 123;
}
};
return local::nested_func();
} int g()
{
int x, y;
struct local {
int & a_;
int & b_;
local(int & a, int & b) : a_(a), b_(b) {}
int operator()()
{
return a_ + b_;
}
} nested(x, y);
x = 99; y = 1;
return nested();
}
assert(g() == 100);How does that work? Not immediately obvious to me.
T common() { ...common sequence of code... }
...
return common();
instead of: goto Lcommon;
...
Lcommon:
... common sequence of code ...
return result;I've done that for years with C and C++. Nested functions are so much nicer and clearer.
Static nested (i.e. local) functions in D can be static. What that does is prevent the function for accessing locals in the enclosing scope(s).
Or just have first class functions, and prototype based inheritance. Way more flexible and powerful than class based inheritance. See JavaScript 5 as an example, ask Crockford.
https://stackoverflow.com/questions/4083356/array-begin-from...
http://docwiki.embarcadero.com/RADStudio/Berlin/en/Migrating...
http://docwiki.embarcadero.com/Libraries/Berlin/en/System.Lo...
It always felt quite natural to me.
http://docwiki.embarcadero.com/RADStudio/Berlin/en/String_Ty...
Besides, there were arrays as well, and TPW had safer strings without that limitation PCharStr.
I found out that GetString converts a Pascal string to C without a length argument!
I think trading some programmer inconvenience for a world with no buffer overruns would have been a good thing, in retrospect!
https://en.wikipedia.org/wiki/Cfront
Interesting.
Apple's Pascal had been extended to the point where there were few true differences between it and C, other than
- strings with busted semantics (size being part of the type being a huge mistake, leading to a proliferation of types like Str255, Str32, Str31, Str64, etc). I should add that C's strings were semantically busted, too, and in more dangerous ways. No way to win :-)
- nested procedures (not terribly useful in practice, IMHO)
- an object syntax, used for Object Pascal and MacApp (a complete, though large and somewhat slow app framework).
- some miscellany, like enums and modules
Apple extended Pascal pretty extensively, adding pointer arithmetic, address-of, variant functions calls, and a bunch of things I've forgotten. I could write some Pascal, then write some C, and squint and they'd look pretty much the same. Most people shrugged and wrote new code C if they were able, and then moved to C++ when CFront became usable.