
The ugliest C feature: &lt;tgmath.h&gt; - slavak
http://carolina.mff.cuni.cz/~trmac/blog/2005/the-ugliest-c-feature-tgmathh/
======
colanderman
_0, 0L, 1 - 1, (((1 - 1))), (void_ )0 and (void _)(1 - 1) are null pointer
constants_

...

 _if one operand is a null pointer constant, the result has the type of the
other operand;_

This is quite possibly one of the most idiotic semantics I've ever seen
specified for a language. Why does the _type_ of an expression depend on the
_partially evaluated_ result of one of its subexpressions? This by itself is
enough to throw out the window any sane reduction semantics (an important
mechanism in language design whereby semantics are defined by specifying how
to transform any program into an equivalent but strictly smaller program),
though I'm sure there are plenty more such constructs in C.

Ridiculous semantics like this are not only the definition of C99; they're the
definition of _designed by committee_.

~~~
evmar
Generally the committees that design these kinds of things are knowledgeable
and careful, so think carefully before accusing them.

In the above case, I wonder if it's related to

    
    
        #define NULL ...something that is a null pointer constant...
    

and then wanting expressions like

    
    
        test ? some_double_pointer : NULL
        test ? NULL : some_int_pointer
    

to have the type one would "expect" rather than whatever type NULL has in
isolation.

~~~
ootachi
It's even simpler. A lot of legacy code out there uses "0" (not NULL or even
(void ∗)0, just 0) in place of NULL. So it's very important for backwards
compatibility that "test ? (double ∗)x : 0" or "test ? 0 : (int ∗)x" return
double ∗ or int ∗, respectively.

I'm not sure why the definition of a null pointer has to be so liberal, but I
suspect there's a backwards compatibility constraint in there.

~~~
jimbobimbo
I'm not sure if this covers C++ only, but here's what Stroustrup has to say:

"In C++, the definition of NULL is 0, so there is only an aesthetic
difference. I prefer to avoid macros, so I use 0."

~~~
kelnos
That definition is indeed C++-only.

~~~
kzrdude
Not sure in which sense it is C++ only. 0 is a null pointer constant in C.

~~~
kelnos
My mistake. I could have sworn that only C++ defined 0 to be equivalent to a
null pointer. I guess my confusion stemmed from the fact that the NULL
preprocessor macro in C++ is actually defined to be just "0" (or a magical-
seeming "__null" in recent versions of g++), whereas in any modern C
implementation I've seen, it's "((void *)0)".

Though there are cases in which passing an unadorned "0" as a null pointer can
be wrong; there's a null-terminated varargs function example here:

<http://c-faq.com/null/null2.html>

------
quizmaster
Uglier than trigraphs?

Also, I've long wondered why complex numbers were added to C. They seem like
an inappropiately feature for a systems language.

~~~
plorkyeran
Trigraphs are certainly _weird_ , but they're also simple enough that I
wouldn't really consider them ugly.

I assume complex numbers were added for the same reason as tgmath.h: a mostly
failed attempt to get people to switch from Fortran to C.

------
jensnockert
C11 has type-generic expressions that allow arbitrary functions to have the
same semantics as the tgmath functions.

------
dlsspy
Seriously? man hcreate

Edit: I guess that isn't so ugly as it is completely pointless. There's a
difference.

~~~
endgame
Oh my. For those situations where you need a hash table, but only one?

~~~
koenigdavidmj
...that can not resize?

------
CGamesPlay
Keep in mind that "the ugliest C feature" was committed in 2000, and the
article was written in 2005. Things were a mite different in 2000, so this was
probably more necessary.

Even if this isn't necessary today, it's a pretty interesting brain exercise.

~~~
kzrdude
glibc still includes similar code. (There are type-switch builtin functions in
gcc that could have replaced it).

------
schwa
For xplatform development on OSX & iOS tgmath OS great.

In fact clang recently added an extension to c for function overloading in a
clean way.

~~~
mikeash
How often do you really need to make sure you get the float versions rather
than simply using the double versions everywhere and dealing with the minor
speed hit? The tgmath stuff is really for scientific computing. For simple
trigonometry on UI elements and such, there's no noticeable advantage to using
e.g. cosf rather than plain cos and letting conversions happen.

------
seabee
tl;dr hacking an unsupported feature (function overloading) into a language
that doesn't support it is ugly and/or results in leaky abstractions.

~~~
aeroevan
He also isn't quite up to speed with Fortran overloading. It is fairly easy to
define interfaces that can call different functions based on input type, but
it still isn't as nice as C++.

<http://pastebin.com/1ewMcDaA>

