Note that Java fits your definition (though it allows one extra type of variable to be accessed, members of the current instance). It is probably the only popular language that supports local functions but not closures.
Also, C++ doesn't suffer from the problem of accidentally capturing variables, since it requires you to explicitly state which variables from the external env you want to reference (with the [a, b] syntax at the start of a lambda declaration; a lambda starting with [] fits your desired constraints).
Thanks for pointing to Java. I have not thought about it, because I use Java only very seldom.
The members of the current instance are not really an extra type of variable.
They are the members of one hidden function parameter. While they are distinguished in the source code, in the translated machine code there is no difference between them and the explicit function parameters.
I agree that this is a good feature of C++, that it avoids the bugs caused by accidental captures by giving control to the programmer on what may be captured.
Nevertheless, perhaps it would have been possible to have a simpler implementation of the C++ lambda-declared functions than with the current function objects, by simply disallowing the capture of stack-allocated local variables.
The thing is, all of these languages have adopted something like closures because they're just very useful. Creating different copies of a function with different values for each item in some local variable/collection comes up very often. Even Java actually supports it, since it does allow you to copy values from the local scope to an inner function scope, even though it doesn't allow you to capture variables. And, since this is a GC language, those values can be references to local objects that can survive after the outer scope exits if they are referenced from the inner scope.
Even in Java, this was there as part of Java 1.0, in the form of instance-scoped inner objects, in a form like this:
for(int i=0; i < arr.length(); i++) {
final int copy = i;
listeners = new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.out.println("pressed button " + copy);
}
}
}
For all such examples of using closures there are alternative implementations that use more efficient mechanisms.
For examples like this, if it is not desired to use a single function with one extra parameter, then multiple functions that differ in using some different constants or different private static variables can be generated by some template mechanism, without using closures.
The problem with closures is that they introduce an overhead in any function that is passed as a parameter or used for some other reason through a pointer, by adding an extra indirection, even if in most cases this is not needed, instead of adding overhead only in the few cases when capturing local variables is really useful (unless something like whole program optimization is used).
C++11 closures are very thin sugar over locally defined structures with an overloaded operator(), which you have been able to define since forever, so I think they do not present any significant implementation complexity.
Also, C++ doesn't suffer from the problem of accidentally capturing variables, since it requires you to explicitly state which variables from the external env you want to reference (with the [a, b] syntax at the start of a lambda declaration; a lambda starting with [] fits your desired constraints).