Hacker News new | ask | show | jobs
by xvilka 3662 days ago
Well, Rust is awesome, but there is a place for C too. I just don't understand lack of the life and no improvements in C for ages. Better typing system (for example _Generic doesn't know uint8_t, etc types - they are just typedefs), 'pure' keyword for functions without side effects, tuples support, deprecate a lot of the things and so on.
3 comments

> I just don't understand lack of the life and no improvements in C for ages.

Well, MSVC still hasn't even fully implemented C99. One of the big draws of C, as I see it, is its wide support on many operating systems and architectures. If you're going to abandon that by using new C features, you might as well use a language with less cruft.

>Well, MSVC still hasn't even fully implemented C99

Neither does GCC. Both don't fully implement C11 either.

Most these features are either things C-Compilers don't need to support themselves. Namely: special integer types can be placed in libraries instead of compilers.

Also bounds checking interfaces are a performance loss and not included in C compilers despite them being part of the C11 standard. (Well they're optional)

It's harder than it looks. If you improve things willy-nilly, then you split the language - some will use the more modern version, some will stay behind.

IMO, a better evolution is to do what the Rust folks have done - define a new language. This way it has a new name and you don't have to qualify which version of 'C' you mean.

_Generic absolutely can handle uint8_t. In fact, the reason _Generic is problematic is precisely because on most implementations uint8_t is a typedef to unsigned char. But in a _Generic list you can't specify multiple compatible types. If you're unsure if uint8_t is compatible with unsigned char, you have to chain multiple _Generic expressions, nesting one inside the default: case like: `_Generic(x, uint8_t: foo_u8, default: _Generic(x, unsigned char: foo_uc, default: baz))`.

So if I specify both unsigned char and uint8_t as cases the same _Generic expression, with GCC 6.1 I get:

  foo.c:6:2: error: ‘_Generic’ specifies two compatible types
    uint8_t: "uint8_t", \
    ^
  ...
  foo.c:5:2: note: compatible type is here
    unsigned char: "unsigned char", \
    ^
and with Apple clang-7001.81 I get

  foo.c:12:22: error: type 'uint8_t' (aka 'unsigned char') in generic association
        compatible with previously specified type 'unsigned char'
Another issue with _Generic: you have to be careful with type promotion, especially because everything smaller than int is quickly promoted to int in most kinds of expressions.

Another issue is type qualifiers: (int) is different from (const int) is different from (volatile int) is different from (const volatile int). _Atomic and restrict increase the permutations.

I have a fuzzy memory that early clang had a wrong implementation of _Generic that didn't obey the standard. But as far as I know, today both clang and GCC have identical behavior. Whether Microsoft implements it compatibly if they add it is another question. For example, Microsoft has an idiosyncratic interpretation of macro tokenization and evaluation that makes implementing certain C99 variable argument macro constructions difficult.