size_t filter(bool (*predicate)(int), int *p, size_t n) {
for (size_t r = 0, w = 0; r < n; r++) {
if (predicate(p[r])) p[w++] = p[r];
}
return w;
}
size_t lowpass(int limit, int *p, size_t n) {
bool lower(int value) {
return value < limit; // use the parent's local variable
}
return filter(lower, p, n);
}
but that requires an executable stack and TFA is about avoiding that part.Pascal supports it (at least Turbo Pascal, no idea about ISO Pascal).
Block structure is traditionally considered an a priori requirement for algorithmic program-
ming languages. Most new languages since Algol-60 have block structure. Reasons exist,
however, to omit the general form of block structure — nested procedure definitions in which
references to identifiers defined in outer procedures are permitted — from programming
languages, especially those intended for systems programming applications. This paper
reviews the concept of block structure and considers its advantages and disadvantages. It
concludes that, in many cases, a module facility is superior to block structure and should be
considered in lieu of block structure in future languages.
[0] https://drh.github.io/documents/blockstructure.pdfI always wondered why C++ only added lambdas, but observing WG21 for a while, I assume this is just a random walk in language design. (not that it is different in WG14)
For the capturing case: to access context that is not available through global variables or function arguments, i.e., the same reason why closures are useful in other languages.
Here's an example, where I have a list of points that I want to sort based on distance to a chosen target point. I can use qsort() which takes an arbitrary comparison function, but has no way to provide context to that function beyond the input arguments:
#include <stdio.h>
#include <stdlib.h>
int main() {
struct Point {
int x, y;
} points[3] = {
{ 3, 1 },
{ 2, 2 },
{ 5, 7 } };
struct Point target = { 4, 5 };
long dsq(const struct Point *p) {
long dx = p->x - target.x, dy = p->y - target.y;
return dx*dx + dy*dy;
}
int compare(const void *p, const void *q) {
long a = dsq(p), b = dsq(q);
return (a > b) - (a < b);
}
qsort(points, 3, sizeof(struct Point), compare);
for (int i = 0; i < 3; ++i) {
printf("%d,%d\n", points[i].x, points[i].y);
}
}
Note here that dsq() is a local function that accesses the `target` variable in the local function scope.The usual workaround in standard C is to pass the necessary context as a function argument. That's why qsort_r() exists, which takes a context argument to be passed to compare(), but that's a non-standard GNU extension.
This practice of passing context pointers around is ubiquitous in C code, and it works, but it can get messy especially if you need access to multiple variables or variables from more than one nested scope. There is also a type safety issue: these context pointers are necessarily passed as void* which means they have to be cast back to the real type before use, which is where bugs can be introduced if the caller and receiver disagree on the actual type.
But I prefer this approach anyhow, as it does not impose any run-time cost for checking the tag, and is easier to optimize.
Nested functions have a different ABI from regular C functions, due to the invisible static chain register that needs to be set up. C has no way of indicating this different ABI, so GCC happily lets you cast a nested function to a C function pointer by creating a little tiny function that puts the right value in the static chain register before calling the nested function. This little tiny function is the trampoline.
Since the trampoline needs to live somewhere, GCC puts it on the stack, requiring the stack to be executable and consequently a whole lot of people hate the feature because it's a walking security nightmare.
For me the main downside of trampolines is that the optimizer can not de-virtualize the trampoline again. This could be implemented, but avoiding the creation of the trampoline in the first place is much better.
int f(int x) {
int g(int y) { ... use x and y ... }
...
h(&g);
...
}
then what the compiled code for f does is construct on the stack a short piece of machine code: mov <well-known register>, <frame pointer>
jmp <start of g’s code>
and &g points to the start not of g’s code but of this snippet on the stack, which has the parent function’s frame pointer compiled into it as a literal constant. The snippet is called a trampoline.Trampolines allow you to simulate that, even when your compiler / language doesn't handle tail calls properly.