15

In C (and so many other "low-level" languages), functions have a type. You can declare a variable with a type that matches a function and can assign a function to such a variable, yet people insists that functions are not first class citizen in C.

Using pointers to functions and passing functions to other functions as arguments is key in several standard functions in C; qsort for example, require a comparison function to be passed or it can't do anything.

It is not uncommon to see "object-oriented" programming in C, by declaring a struct with several variables with function-types. Callbacks can be and often are (if not always -- I can't imagine any other way to do it) implemented using variables with function-types or structs with members with function types.

So, why aren't functions considered first class citizens in C?

(I'm sure this is duplicate, but I can't seem to find any similar questions here)

Clearer
  • 2,166
  • 23
  • 38

3 Answers3

23

There's a really good answer by Andreas Rossberg on a Scala question (near-duplicate) that happens to explain why functions in C/C++ aren't first class functions. To quote:

Being "first-class" is not a formally defined notion, but it generally means that an entity has three properties:

  1. It can be used, without restriction, wherever "ordinary" values can, i.e., passed and returned from functions, put in containers, etc.

  2. It can be constructed, without restriction, wherever "ordinary" values can, i.e., locally, in an expression, etc.

  3. It can be typed in a way similar to "ordinary" values, i.e., there is a type assigned to such an entity, and it can be freely composed with other types.

For functions, (2) particularly implies that a local function can use all names in scope, i.e. you have lexical closures. It also often comes with an anonymous form for construction (such as anonymous functions), but that is not strictly required (e.g. if the language has general enough let-expressions). Point (3) is trivially true in untyped languages.

...

  • Functions in C/C++ are not first-class. While (1) and (3) are arguably available through function pointers, (2) is not supported for functions proper. (A point that's often overlooked.)

Emphasis mine

Community
  • 1
  • 1
hnefatl
  • 5,860
  • 2
  • 27
  • 49
  • 1
    This is a very Scala oriented point of view (as you would expect from someone who defines it from a Scala point of view). I just don't see any real difference between `int * ` and `(int()) *`, from a "first-class" point of view. – Clearer Jan 04 '18 at 09:38
  • Of course you would have to call a function to get anything meaningful from it, just like you have to dereference a pointer to get anything meaningful from it too. You have to use everything in the way it's supposed to be used or it's useless. – Clearer Jan 04 '18 at 09:51
  • 1
    Don't c++ lambdas solve 2nd point? – Osman-pasha Nov 16 '22 at 16:27
  • 1
    Lambdas construct closures, which _are_ first class citizens. But "ordinary" functions, like `void foo() {}`, are not first class. – hnefatl Dec 09 '22 at 19:03
7

Adding an example to the theory explanation by hnefatl. In C, int values are first class. We can add two int values, creating a new int value:

 int add(int a, int b)
 {
   return a + b;
 }

Similarly in Haskell, we can compose two functions (of appropriate type) to create a new function:

 compose f g = f . g

h = compose f g is the function such that h(x) = f(g(x)).

Such an operation can't be done in C, to my knowledge. The same effect can be achieved through other means in C of course. But we cannot compute new functions as easily and naturally as we can numbers.

jforberg
  • 6,537
  • 3
  • 29
  • 47
2

I think wikipedia has a better explanation of this concept. The key to first-class functions is whether a language supports closures, which raises the funarg problem if a returned function refers to variables defined in the outer environment. Apparently, C doesn't support that.

Nick X
  • 176
  • 1
  • 7