2015-06-20

Type-generic functions (overloading) in C11

As per Michael Stoffregen suggestion in the comment, I've tried to move arguments outside and it worked (even with gcc 4.9.2)! So I can finally say C(11) has Fortran-like function “overloading” — type generic functions.

I have often wondered why C hasn't any kind of function overloading. The typical answer is that we don't want to live with name mangling in C — the hell of the C++ — that would break a lot of things which must stay as they are. I agree… except that you don't need to implement it the C++ way when you have a bright example like Fortran.

Now it seems like C11 has something that could give us function overloading (and other tricks)… maybe in C11 you shouldn't say “overloaded function”, but “type-generic function”, I suppose. Anyway… I will use them interchangeably.

I hoped for something similar to Fortran… Instead, we have _Generic: C11 introduced this macro (sort of) which allows to select a function1 according to a type.

I have found it unsatisfactory2, unless you consider it more like a new tool for powerful tricks rather than a way towards type-generic functions. Also, it seems they had just a single usage scenario in mind: tgmath.h. I daresay it's hard to think to use this _Generic in a generic scenario…

What I have seen so far…

  • No way of overloading operators. Maybe there are many who think that such a possibility can help in making code uglier, less clear and so on — but this is, and always has been and always will be, a programmers' sin: let “good” programmers choose when it is ok to use such a feature and when it is not… (Macros, after all, are “dangerous”: you shall use them sparingly and you shall handle them with care…)
  • It's easy to overload functions according to a single argument; tricks to cope with non-single argument functions may exist and be cool, but… (e.g. see this stack overflow answer or this question; also, take a look at this idea about how generic pow could be done…)
  • It seems it does not work with all types — maybe just for “simple”, primitive types and “aliases”?

My test (simple and basic). (Modified according to Stoffregen's suggestion — he was right!)

Taste of Fortran

Let's compare how Fortran intends type-generic functions. Of course Fortran is not C and C is not Fortran… But good ideas can always be borrowed.

You can also use interface operator(+) (say) if you want to “overload” +, or interface assignment(=) to overload the assignment operator.

Right now I have no idea how this could be done keeping the C syntax and “taste”.

At this point, before Stoffregen-suggested fix, I had written:

Anyway, with C11 and _Generic, in my opinion C has lost a chance to have generic (!) type-generic functions done quite well. Therefore I'll wait the next revision of the standard before yelling “at last!”

Maybe they are not perfect yet, but this judgement must be made less harsh.


  1. Since it works like a macro, we can produce any string, even so that the code becomes syntactically broken. As it is for preprocessor's macros.

  2. I have tested this new feature with gcc 4.9.2 (just compiled) and clang 3.0-6.2 (package in Debian Wheezy).

3 comments:

  1. I know your post is years old, but I'm playing around with generic C programing and this was one of the top(ish) google results so I felt compelled to comment. In the C example, I think you're doing it wrong. Change it to this and rock and roll:

    /* this should work.. the (X,Y) are moved outside of the generic () block */
    #define sumx(X, Y) _Generic((X), \
    int: sum2l, \
    long: sum2l, \
    double: sum2d, \
    float: sum2d, \
    vec2d: sum2v ) ((X), (Y))

    ReplyDelete
    Replies
    1. That's interesting. Anyway it forces a different syntax in two cases: don't forget "sum" works just fine — I wonder why I must write it differently when I don't use a primitive type! It's odd.
      Moreover, now I have a more recent gcc version, maybe I should also try it again, maybe it was a specific issue of that version. I will update the post accordingly.
      Thanks for the feedback.

      Delete
    2. At last I tried it: you were right (of course).

      Delete