C has first-class functions support, but I don't think it's very easy to define such interfaces in C. Closures and automatic memory management seem to be the "magic dust" that makes this nice to use, first-class functions are necessary but not sufficient.
The definition of first-class functions is the ability to treat functions as data, which C supports. Yes, they are cumbersome to work with, since they must always be defined at top level, but that is just missing syntax sugar. GCC even allows nested function definitions.
> Yes, they are cumbersome to work with, since they must always be defined at top level, but that is just missing syntax sugar.
It's not just syntax sugar. Try writing a function that takes an array of integers and an integer x, and sorts the array mod x by calling qsort. In C this is not just cumbersome but impossible.
static int reg;
int cmp(int a, int b) {
return a%reg - b%reg;
}
void qsortModX(int[] a, size_t len, int x) {
int tmp = reg;
reg = x;
qsort(a, len, sizeof(*a), cmp);
reg = tmp;
}
We could even wrap qsort so that you could pass something much closer to a closure to it :
With this, you can define a `struct closure` that encapsulates a function and some data and use that to pass to qsort_cls. You can even make it thread safe by using thread local variables instead of globals.
Basically, if you want higher-order functions in C, you can do it, but you need to take a context pointer and a function which accepts a context pointer. The writers of qsort didn't think of that, so we had to resort to global variables to do it, but you could also re-write qsort to avoid the need for the global variable.
As I said, we're missing a lot of syntax sugar, but we can still work with functions as first class objects in pure C.
What you're proposing requires extra work to be threadsafe, is even less typesafe than normal C functions (you've lost checking that `ctx` is actually an `int`), requires you to reimplement it for each standard function you want to use, and is significantly syntactically more cumbersome even after you've done all that. If that's "first class" then how bad would things have to get before you called them "second class"?
I am sympathetic to what you're saying, and in the end this is just a matter of definitions.
I would note though that with C's type system, you always have to choose between type safety and genericity, this is not exclusive to higher order functions. C doesn't have a notion of threads or thread safety, so talking about thread safety in pure C does not make sense. And the fact that the designers of the stdlib didn't think about supporting closures still doesn't mean that the language itself doesn't support them. Other foundational libs, like pthreads, do have support for this style of closures built in.
> with C's type system, you always have to choose between type safety and genericity, this is not exclusive to higher order functions.
True, but functions defined via some kind of "struct closure" scheme are non-typesafe even when monomorphic (e.g. if all the types are int).
> C doesn't have a notion of threads or thread safety, so talking about thread safety in pure C does not make sense.
I'd hold that a function that relies on a global variable is noticeably second-class in a number of ways. Multithreading is one place where this comes up, but you also have to be careful about using it in a recursive context, or use in a library that might be called from more than one place.
> And the fact that the designers of the stdlib didn't think about supporting closures still doesn't mean that the language itself doesn't support them.
Any Turing-complete language "supports" any feature of any other language in a sense, because it's always possible to emulate that other language. If we say functions are first class then we mean not only that it's possible to represent functions as values (because that will always be possible), but that functions represented this way are just as good values as the language's built-in notion of values, and just as good functions as the language's built-in notion of functions.
My understanding agreed with your respondent. I haven't dug deeper but per wikipedia there's a split in the CS community as to whether function literals are necessary for functions to be first class. I think we all agree on the reality of the situation, whichever way we decide that ambiguity.