
Function overloading in C - bemmu
https://gist.github.com/barosl/e0af4a92b2b8cabd05a7
======
Animats

        #define add(a, b) _Generic(a, int: addi, char*: adds)(a, b)
    

Just because you can doesn't mean you should. Someday, someone will have to
read that code. Note that when "add" returns a string, it's done an
allocation, but for the integer case, it hasn't called "malloc". Now you'll
now need to know the type to get rid of it.

Back in C99, generic trig functions were put in to make the number-crunching
people happy. After all, FORTRAN has them. Everybody was tired of different
versions of math libraries for "float" and "double". Then in C11, the
mechanism behind that, "_Generic", was exposed. Now, anybody can use it. But,
probably, they shouldn't. [1]

[1] [http://www.robertgamble.net/2012/01/c11-generic-
selections.h...](http://www.robertgamble.net/2012/01/c11-generic-
selections.html)

~~~
maxlybbert
> Just because you can doesn't mean you should.

The fact that it's new doesn't mean it's in bad taste.

GCC has had a similar mechanism in C for decades. It was experience with that
mechanism, and similar extensions in other compilers, that led to it being in
the C Standard.

------
kazinator
This whole _Generic stuff is a mistake. There is already a descendant dialect
of C which has nice overloading, namely C++.

Analogy: imagine some people aren't happy with the new Fortran. Fortran 66 is
the best language ever, and the only flavor of Fortran anyone should use ...
except: they like a couple of features from Fortran 2008 and Fortran 90.

So, they whip out the Fortran 66 standard and fork it to create "Fortran
Classic" where they just adopt what they like from mainstream Fortran --- and
in a totally incompatible way!

And that's basically what C is doing now.

~~~
xamuel
But the OP title is misleading, this isn't function overloading at all. It's
macro overloading. Subtle but important difference. For example, you can't
pass the OP's "add" around as a function pointer. You can't declare its
prototype in an outside file (leaving the linker to link it in) without
putting its full definition in said outside file. Etc.

It also gives, IMO, better error messages than C++. If we take OP's code and
change a and b from int to long, we get:

    
    
        test.c:20:24: error: controlling expression type 'long' not compatible with any generic association type
        printf("%d\n", add(a, b)); // 3
                           ^
        test.c:16:28: note: expanded from macro 'add'
        #define add(a, b) _Generic(a, int: addi, char*: adds)(a, b)
    

This is better than the situation in C++ where it would say the function does
not exist, and then go through every function with that name (possibly quite a
lot) and say why each one doesn't work.

~~~
kazinator
I _want_ to pass a function as a pointer even though it is overloaded. C++
supports that. For instance if we do:

    
    
       int (*p)(int, int) = add;
    

overload resolution kicks in there.

I want detailed error messages about overload resolution. Maybe not all the
time: give me the executive summary ("no suitable overload of add was found")
and the details if I specify some "-Woverload-detailed" option or whatever.
That's a quality of implementation matter; neither ISO C nor ISO C++ spell out
what diagnostics should look like and how detailed they should be.

Token-level macros are hacky cruft that shouldn't be used as the development
bed for new features, period. All this stuff ignores 35 years of progress in
the C dialect scene alone, not to mention 60 years of progress in general.

Above, add isn't even what is understood in computing as a "first class
function". If we make it into some hacky macro, we are taking away even that
second class status away from it.

~~~
nothrabannosir
_> I want to pass a function as a pointer even though it is overloaded. C++
supports that._

That's his point: C _Generic and C++ are not the same. Which one is better was
not his point, just that they're different.

~~~
kazinator
> _Which one is better was not his point, ..._

The comment is loaded with judgment, and the word "better" actually occurs.

------
o87dv
I was expecting something interesting. Generic selection is built into the
language:

[http://en.cppreference.com/w/c/language/generic](http://en.cppreference.com/w/c/language/generic)

~~~
cremno
I recommend reading the notes section and better yet the following blog entry
before one decides to use _Generic with less trivial types:

[https://gustedt.wordpress.com/2015/05/11/the-controlling-
exp...](https://gustedt.wordpress.com/2015/05/11/the-controlling-expression-
of-_generic/)

------
nautical
This answer is more detailed ..

[http://stackoverflow.com/questions/479207/function-
overloadi...](http://stackoverflow.com/questions/479207/function-overloading-
in-c/13010401#13010401)

------
halosghost
This is a very simple example. It only checks the type of the first parameter.
_Generic can operate on all parameters, it just leads to an exponential
increase of mess for each additional parameter handled.

While I like _Generic in C11, there is no doubt that it is not as powerful or
handy as Templates (this coming from someone who does not really enjoy Cxx
templates).

~~~
dllthomas
It's hard to say what's more powerful. Certainly templates involve more
computation, but _Generic can do some things templates can't (for good and for
ill) and vice-versa.

~~~
halosghost
Well, since templates are turing complete, I would tend to say that they are
more powerful. But they work very differently. Templates do code generation
and _Generic is just a fancy-pants type-based macro-dispatch.

Like I said, I do not think _Generic is a bad thing (though it can get really
messy—which is not to say that Templates can't), just that the example given
in the OP is a bit contrived.

~~~
dllthomas
It is _computationally_ more powerful, sure. If that's what you'd intended to
be talking about, then fine. But that is a distinct notion from "you are able
to do more with it" \- which is typically the more relevant bit when
discussing the power of a feature in a programming language outside a
restricted academic context.

(Incidentally, other things being equal - including ability to get done the
thing you want to get done - "Turing complete" is a bug, not a feature!)

Expanding a little - "Turing complete" means that your system is capable of
_computing_ anything that can be computed _in some encoding_ , but that
doesn't mean that it is linked to the rest of the world in a way that will do
something useful with that encoding of the result.

Token-manipulating C macros, while obviously of less powerful in the sense of
computability, can do things that templates cannot do (name mangling,
annotations, compiler pragmas) - and with _Generic, any of these can now be
type directed. Of course, with great power comes the responsibility never to
use half of that... but that's pretty true of C++ as well :p

------
travjones
I don't program in C, but I can understand most of this code; However, I'm not
sure where the "function overloading" part comes in or why it's significant.
Could someone explain?

~~~
judofyr
This is a good explanation:
[https://www.reddit.com/r/programming/comments/3en2px/til_you...](https://www.reddit.com/r/programming/comments/3en2px/til_you_can_use_function_overloading_in_c/ctgj9zv)

------
RoboSeldon
Works with Clang and GCC.

Obviously, Visual Studio doesn't work (they have almost complete support for
C99 though, so maybe in a few years they will include C11 support).

~~~
detaro
Unlikely, unless they need it for C++. Even C99 only gets better when they
need parts of it for C++ anyways, and is not developed further.

------
crystalgiver
Interesting approach, this is how I do it:

    
    
       cc -std=c++14
    

No preprocessor necessary! Also it checks the type of both arguments.

~~~
ambrop7
Indeed. No need to use "complex" features like RAII/RTTI/exceptions.
Generally, I see features like classes, overloading and templates as
"compatible" with C-style coding.

