15 comments

[ 2.9 ms ] story [ 57.1 ms ] thread
What was in the email that caused such a change in heart?
I assume that the exact email itself is irrelevant, but the committee just never thought about them before [1] and found it reasonable.

[1] N2645: "Note that #ifdef has been present since C89 and I couldn't find any papers in the WG14 log that seemed to touch on this topic."

> if I had a time machine, I’d blow #ifdef up and just make people used #if defined(...), it’s better and more flexible and represents the same functionality

Hear hear. This sort of union of a flow-control construct with a specific type of expression, seems an ugly thing. That it may save typing a few characters, doesn't count for much.

I'll shake my cane here. It's a mistake to add unnecessary features to the C preprocessor when we should be putting that sucker to bed already. The CPP was a marginally bad idea 45+ years ago when it was invented, and it only hurt language tooling when C took off in the 80s and wasn't replaced by something better.

I guess you can always write a pre-preprocessor to fix things up for an older preprocessor. But, ugh.

I think it was unfortunate that the C preprocessor syntax is completely different from that of the C language itself. PL/I's preprocessor syntax is (approximately) a subset of the normal PL/I syntax (with a % sign in front to distinguish preprocessor instructions from code). I think that's a better approach.

That said, there is so much C code in existence assuming the existing C preprocessor, it is more feasible to add new features to the existing one than replace it with something new and incompatible.

I wish they'd add some better syntax for multi-line macros. So instead of:

  #define TRY(what) \
      do { \
         int r = (what); \
         if (r != 0) \
            return r; \
      } while (0)
you could write something like this:

     #macro TRY(what)
        do {
           int r = (what);
           if (r != 0)
               return r;
        } while (0)
     #endmacro
Get rid of the backslashes (which are easy to screw up). It would also enable you to use #if conditionals inside the #macro block, so you could easily write conditional macros.

Also, maybe instead of the do { ... } while (0) trick, #macro could automatically insert do { } while (0), maybe say if the #macro had a { on the same line:

     #macro TRY(what) {
        int r = (what);
        if (r != 0)
           return r;
     }
     #endmacro
Some kind of looping support (e.g. #while) would also be great:

     #macro NULLS(count)
     #   local i 0
     #   while (i < count)
             NULL,
     #       define i i+1
     #   endwhile
     #endmacro
In the above, #local is #define but local to the #macro block.
Looping is already totally doable, up to a finite maximum number of iterations. Local variables and the like can be simulated through suitably clever preprocessor definitions and logic, too. The syntax and trickery you need to take advantage of it is thoroughly, thoroughly unpleasant though.

For anyone curious about the practicality of that sort of thing, A CPS macro continuation machine like https://github.com/rofl0r/order-pp/blob/master/inc/order/cm.... would give you about 18 quintillion loop iterations if my math was right; double the length of that file and you’d have more loop iterations than atoms in the universe.

I think it would have been much better to design an alternative with the same feature set (i.e. code generation through substitution), but better overall design in terms of hygiene and scoping, as opposed to what C++ has been trying to do by making ad-hoc replacements for some of the tasks you would want to use the preprocessor for, and then admonishing anyone who uses it because of limitations in the replacements. Macros are fundamentaly extremely useful, and the CPP is bad because it's a bad implementation of the concept (as well as leant on far too hard for importing interface definitions), not because the concept itself is bad.
I agree that #if defined(...) is better but we don't have a time machine so I'm glad that the proposal isn't accepted. If we are going to keep #ifdef in the language (and we don't really have a choice) we may as well make it consistent and usable.
If they're adding `elifndef` to the C preprocessor they should definitely add `elsunless` to Perl.
I expect the first few years of this being used will almost exclusively consist of people replacing instances of it with `#elif defined FOO` for use with older compilers or in code (e.g. headers) that also needs to be compilable with a C++ compiler.

Sure, in isolation it's more orthogonal. But it's hard to see this as a real value add when amortised against the compatibility headache, when the arguably cleaner alternative of `#if defined FOO ... #elif defined BAR ... #endif` is already available.

(Incidentally (1) you can choose to also spell out `#ifdef FOO` as `#if defined FOO` when it's one of a list of alternatives like this, so they all look similar; (2) there's no need for excess parentheses with `#if defined` either.)

#elifndef would make a good Harry Potter spell.
Why does the C preprocessor need the #elif syntax at all? C doesn't have it, it just achieves "else if" by embedding the second if statement inside the else clause. But maybe that wouldn't work in the preprocessor?

    #if FOO
        foo();
    #elif BAR
        bar();
    #endif

    #if FOO
        foo();
    #else
        #if BAR
            bar();
        #endif
    #endif
I guess it works but it's clunkier.
For the same reason as in other languages (e.g., Perl, bash) with (effectively, in Perl's case) an explicit end-if keyword: so that you don't need a whole bunch of #endifs at the end of your conditional, one for each #if or #else … #if.

C itself doesn't need this, because you can write `else if …` without needing to put another layer of braces around the subordinate `if` statement.

For the case of multiple else if’s using the below case would you need to start nesting them to get the same functionality as #elif?