Function Overloading

B

Ben Pfaff

Guillaume said:
Indeed, but something worse is intriguing: the macro expands to an
instruction block. I don't see how a block (some instructions surrounded
by braces { }) can be an R-value? Seems to be a GCC trick, but
apparently forbidden by the standard (or did I miss anything here?).

Dan Pop was trying to make a point, not present standard C code.
The above is not standard C code.
 
D

Dan Pop

In said:
GNU C does indeed support "overloading" via macros, in a generalized
form that handles the specifics required for the ugly C99 version.
(The actual macro needs to use __builtin_classify_type so that it
can handle integers and complex arguments.)

Does __builtin_classify_type count as a GNU C feature, or is it merely
an undocumented gcc feature?

The documented builtin relevant here is __builtin_types_compatible_p
but I'm not sure if *any* builtin qualifies as a GNU C feature.
Perhaps a better way to phrase it is this. Aside from the exposure
as a macro (which I grant is a very large "aside"), the sequence:

#include <tgmath.h>

float a; long double b; double complex c; int d;
...
a = sin(arg); b = sin(arg); c = sin(arg); d = sin(arg);

*looks* (syntactically) like an overloaded function, and *acts*

(semantically) like an overloaded function -- so what should we
call it?

Whatever Fortran calls it.
Overloaded functions are already just syntactic sugar.

But it's a syntactic sugar that works behinds the scenes in an
undocumented way (the functions that get overloaded have the same name,
which is not the case with <tgmath.h>) and is available to the user to
consume it as he sees fit.

Along the same lines, C "supports" operator overloading, because
several operators perform multiple operations, according to the number
and type of their arguments.

Dan
 
G

Guillaume

Overloaded functions are already just syntactic sugar.

I agree, I think they also are syntactic sugar in C++.

I see in them more potential risks than benefits.
 
G

Guillaume

What risks do you see?

1. Code becomes quickly difficult to understand. Or worse: it makes you
think you understand it, when you actually don't.

2. As any other kind of superfluous facility, it's an incentive to use
and abuse it.

3. There can be some nasty "ambiguous overloading" bugs.
I've seen it many times in C++ code. Not all compilers are able to
catch them. It can especially happen with operator overloading.

4. It makes you "overload" functions that you think are functionnally
similar. It may later on turn out that they are not so similar, but
by the time you realize that, hundreds of other functions may depend
on them. A hell to maintain.

5. It's usually some overhead at run-time (although this point may not
qualify as a "risk"). And a huge overhead at compile time, which has
its importance when you work on very big projects (might not want
to wait for hours while your code compiles...)

6. Speaking of overhead, they often imply security issues through the
use of "v-tables". I'm not getting into details here, but many papers
have been written on the subject.


I can't think of anything else right now, but I may miss some other
potential risks. You may not agree with my views...
 
M

Martin Dickopp

Guillaume said:
1. Code becomes quickly difficult to understand. Or worse: it makes you
think you understand it, when you actually don't.

This depends on what the programmer is used to. The following statement
is just as equally valid: Function overloading makes the code easier to
understand.
2. As any other kind of superfluous facility, it's an incentive to use
and abuse it.

Most features in most programming languages are superfluous. If you
were to ban everything for C that is superfluous (so that in the
resulting language, everything can be done in just one way), not much of
C as we know it would remain.
3. There can be some nasty "ambiguous overloading" bugs.
I've seen it many times in C++ code. Not all compilers are able to
catch them. It can especially happen with operator overloading.

I've seen buggy compilers too, but compiler bugs are hardly the fault of
the feature.

<OT>
C++ has complicated, but /well-defined/ overloading resolution rules.
See the C++ standard for details.
4. It makes you "overload" functions that you think are functionnally
similar. It may later on turn out that they are not so similar, but
by the time you realize that, hundreds of other functions may depend
on them. A hell to maintain.

Almost all features can be abused, that's not specific to function
overloading.
5. It's usually some overhead at run-time (although this point may not
qualify as a "risk"). And a huge overhead at compile time, which has
its importance when you work on very big projects (might not want
to wait for hours while your code compiles...)

Function overloading can trivially be implemented using "name mangling",
which involves no run-time overhead.
6. Speaking of overhead, they often imply security issues through the
use of "v-tables". I'm not getting into details here, but many papers
have been written on the subject.

"V-tables" are not required for function overloading.
I can't think of anything else right now, but I may miss some other
potential risks. You may not agree with my views...

As is probably obvious by now, I don't. :)

Martin
 
D

Dan Pop

In said:
There's no way to avoid risking that, apart from not programming.

Until now I've been quite successful at avoiding this risk while
programming in C.

Dan
 
N

Neil Cerutti

Until now I've been quite successful at avoiding this risk
while programming in C.

It depends how you define risk. I would say that, even though
you haven't yet written code that you believe has become a hell
to understand and maintain, you have still risked doing so by
writing programs. If you weren't risking it, there would be no
reason to follow good programming practice.
 
N

Neil Cerutti

1. Code becomes quickly difficult to understand. Or worse: it
makes you think you understand it, when you actually don't.

2. As any other kind of superfluous facility, it's an incentive
to use and abuse it.

3. There can be some nasty "ambiguous overloading" bugs. I've
seen it many times in C++ code. Not all compilers are able to
catch them. It can especially happen with operator overloading.

4. It makes you "overload" functions that you think are
functionnally similar. It may later on turn out that they are
not so similar, but by the time you realize that, hundreds of
other functions may depend on them. A hell to maintain.

5. It's usually some overhead at run-time (although this point
may not qualify as a "risk"). And a huge overhead at compile
time, which has its importance when you work on very big
projects (might not want to wait for hours while your code
compiles...)

6. Speaking of overhead, they often imply security issues
through the use of "v-tables". I'm not getting into details
here, but many papers have been written on the subject.

Based on that last point, I think we might have different things
in mind. The function overloading I thought you meant is static,
compile time polymorphism, like that used for C's operators.
 
D

Dan Pop

In said:
It depends how you define risk. I would say that, even though
you haven't yet written code that you believe has become a hell
to understand and maintain, you have still risked doing so by
writing programs. If you weren't risking it, there would be no
reason to follow good programming practice.

That's the point: by following good programming practices I avoid the
risk.

Dan
 
R

Ross Kendall Axe

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Martin Dickopp wrote:
|
[snip]
|
| Function overloading can trivially be implemented using "name mangling",
| which involves no run-time overhead.
|

But leads to annoying link-time problems when used with libraries...

[snip]
|
| Martin
|
|

Ross
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFAo+1S9bR4xmappRARAqz+AJ96zPp8HZlBByG30/LMOehSzy0cdACfRGGV
n01s6jTKPiF6tTGOfhbBuu4=
=/zzp
-----END PGP SIGNATURE-----
 
M

Martin Dickopp

Ross Kendall Axe said:
Martin Dickopp wrote:
|
| Function overloading can trivially be implemented using "name mangling",
| which involves no run-time overhead.

But leads to annoying link-time problems when used with libraries...

Not really. Name mangling is common among C++ implementations, yet no
annoying link-time problems arise with C++ programs.

Martin
 
R

Ross Kendall Axe

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Martin Dickopp wrote:
|
|
|>Martin Dickopp wrote:
|>|
|>| Function overloading can trivially be implemented using "name mangling",
|>| which involves no run-time overhead.
|>
|>But leads to annoying link-time problems when used with libraries...
|
|
| Not really. Name mangling is common among C++ implementations, yet no
| annoying link-time problems arise with C++ programs.
|
| Martin
|
|

Fair enough, I'll believe you :) I don't use C++ personally, but I
heard there were problems sometimes, but it could just have been in a
theoretical sense.

Ross
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFApAxh9bR4xmappRARAus/AJ44PDXYLKpLynbQW+ibj2vY9nJtEQCgmVNA
87aQ2Tqa0Fsz4hJ33pMisxQ=
=wy5x
-----END PGP SIGNATURE-----
 
M

Martin Dickopp

Ross Kendall Axe said:
Martin Dickopp wrote:
|
|
|>Martin Dickopp wrote:
|>|
|>| Function overloading can trivially be implemented using "name mangling",
|>| which involves no run-time overhead.
|>
|>But leads to annoying link-time problems when used with libraries...
|
|
| Not really. Name mangling is common among C++ implementations, yet no
| annoying link-time problems arise with C++ programs.

Fair enough, I'll believe you :) I don't use C++ personally, but I
heard there were problems sometimes, but it could just have been in a
theoretical sense.

To be fair, there /were/ (maybe still are) problems, but they were not
related to the fact that name mangling was used, but that different
compilers used it in different ways. You could therefore not necessary
link together code compiled by two differernt C++ compilers, even on the
same system.

The same problem would arise with two C compilers if they (e.g.) passed
arguments to functions in different ways. So this is nothing specific
to C++ or name mangling.

Martin
 
R

Ross Kendall Axe

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Martin Dickopp wrote:
|
|
|>Martin Dickopp wrote:
|>|
|>|
|>|>Martin Dickopp wrote:
|>|>|
|>|>| Function overloading can trivially be implemented using "name
mangling",
|>|>| which involves no run-time overhead.
|>|>
|>|>But leads to annoying link-time problems when used with libraries...
|>|
|>|
|>| Not really. Name mangling is common among C++ implementations, yet no
|>| annoying link-time problems arise with C++ programs.
|>
|>Fair enough, I'll believe you :) I don't use C++ personally, but I
|>heard there were problems sometimes, but it could just have been in a
|>theoretical sense.
|
|
| To be fair, there /were/ (maybe still are) problems, but they were not
| related to the fact that name mangling was used, but that different
| compilers used it in different ways. You could therefore not necessary
| link together code compiled by two differernt C++ compilers, even on the
| same system.
|

Glad I wasn't imagining the C++ name mangling problem after all.

| The same problem would arise with two C compilers if they (e.g.) passed
| arguments to functions in different ways. So this is nothing specific
| to C++ or name mangling.

Quite true. Under Windows, for example, there are 2 popular calling
conventions, either caller pops the arguments off the stack or the
callee pops the arguments. Of course, you could also imagine args being
passed in registers as an optimisation, or any number of other
platform-specific methods. Indeed, Linux kernel modules compiled with
one version of gcc are not expected to work with a kernel compiled with
another version of gcc.

That said, I would say that C's simplicity make calling convetions much
easier to agree on, and function overloading (with it's associated name
~ mangling) exacerbates to problem.

|
| Martin
|
|

Having thought a bit more, I remember now that the linking problems I
was originally thinking of referred more to classes than overloaded
functions. Again, I'm sure that linking a class is *theoretically* not
much harder than linking standard C functions, but the complexity of the
problem means that there are many more plausible ways of doing it, thus
leading to disparities between different compilers.

However, with something as simple as a C function call, there are very
few obvious ways to do it.

Ross
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFApWbN9bR4xmappRARAkX+AJ47O9P0uKS8ge/KSXiC8kr6i6k4ugCgrFpM
UPVEVryJJvyXUi+3RAMuPFc=
=CU20
-----END PGP SIGNATURE-----
 
J

James Kanze

|> > What risks do you see?

|> 1. Code becomes quickly difficult to understand. Or worse: it makes
|> you think you understand it, when you actually don't.

You don't need function overloading for that:).

|> 2. As any other kind of superfluous facility, it's an incentive to
|> use and abuse it.

As you say, it is true for just about any facility. It's a negative
point; to justify any facility, you have to provide offsetting positive
points.

|> 3. There can be some nasty "ambiguous overloading" bugs. I've seen
|> it many times in C++ code. Not all compilers are able to catch them.
|> It can especially happen with operator overloading.

The answer to that is simple: don't use C++'s complex rules for overload
resolution.

|> 4. It makes you "overload" functions that you think are
|> functionnally similar. It may later on turn out that they are not so
|> similar, but by the time you realize that, hundreds of other
|> functions may depend on them. A hell to maintain.

See point 1. You can misname functions just as badly without
overloading.

|> 5. It's usually some overhead at run-time (although this point may
|> not qualify as a "risk"). And a huge overhead at compile time, which
|> has its importance when you work on very big projects (might not
|> want to wait for hours while your code compiles...)

Overloading is fully resolved at compile time. Runtime overhead is 0.

The amount of compile time overhead depends on the complexity of the
overload resolution rules (see point 3) -- although it is never totally
free, it doesn't have to be huge.

|> 6. Speaking of overhead, they often imply security issues through
|> the use of "v-tables". I'm not getting into details here, but many
|> papers have been written on the subject.

I think you're thinking of virtual functions, not overloading.
Overloading doesn't involve v-tables or any runtime mechanism.

In the end, like everything else, it is a tradeoff. Generally speaking,
concerning the positive aspects, I would say:

- It is almost essential to write good mathematical software (and some
business software). But for that, you need not only function
overloading, but full user defined types, with operator overloading
as well. What good is being able to write sin(aBigDecimal) if I have
to write bigDecimal1.add( bigDecimal2 ), rather than bigDecimal1 +
bigDecimal2?

- It can be very useful in certain cases of generic programming: C++
templates or perhaps some fancy macro generated code in C.

Offsetting those advantages is that the overloading rules almost have to
be complicated in C/C++, given the number of implicit conversions the
languages support. And it isn't so much overloading itself that costs,
it is the complexity of the overload resolution rules, which means that
1) the compiler has a lot of work to do, and 2) even more important, it
becomes a real guessing game for whoever reads to program to know what
function actually is going to be called.

I work mostly in C++, where I have overloaded functions. From
experience, I really only use them in the following cases:

- constructors -- C++ requires all constructors for a given class to
have the same name, so you don't have much choice,

- smart pointers -- this is a very C++ specific technic for resource
management, and totally irrelevant in C, and

- my BigDecimal class, which implements full the decimal arithmetic I
need for some commercial applications.

IMHO, only the last is in the least way relevant to C, and I'm not sure
that just simple function overloading is the best answer (in C).
 
J

James Kanze

|> > Martin Dickopp wrote:

|> > | Function overloading can trivially be implemented using "name
|> > | mangling", which involves no run-time overhead.

|> > But leads to annoying link-time problems when used with
|> > libraries...

|> Not really. Name mangling is common among C++ implementations, yet
|> no annoying link-time problems arise with C++ programs.

That's not really true. If I compile a function in C with gcc, I can
link it with an application compiled with Sun cc; if I compile a
function in C++ with g++, I cannot link it with an application compiled
with Sun CC. The linker complains.

In fact, there are many reasons for this, and the compilers use
different mangling schemes intentionally, so that I get the error at
link time, rather than some strange run-time error. There would be no
reason for C compilers to use different manglings. But they probably
would; gcc would use a mangling compatible with g++, and Sun cc a
mangling compatible with Sun CC.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top