Mixin C

Paul Backus snarwin at gmail.com
Sat Mar 23 19:02:52 UTC 2024


On Saturday, 23 March 2024 at 02:51:31 UTC, Steven Schveighoffer 
wrote:
>
> So the entirety of `stdio.h` is included in the body of the D 
> main function? Is that wise?

In this specific example, it's overkill.

In general...is there a better alternative? The C preprocessor is 
a blunt instrument, and if we want to have full support for it, 
we are going to have to live with the consequences of that 
bluntness.

With Mixin C, the D programmer at least gets to choose whether 
they would rather pay the cost of `#include`-ing C headers 
multiple times, or the cost of translating preprocessor macros by 
hand.

> The other problem is if you want to use C expressions in D. For 
> example, let's say you have the C definition:
>
> ```c
> #define PI 3.14159
> ```
>
> How can I use this in D land? I could assign it to a variable 
> maybe?
>
> ```d
> mixin(C) {
>    #include "pidef.h"
>    double PI_ = PI;
> }
> ```
>
> Note, I have to use a new name. And it has to be a variable, 
> because that's all you can do in C. What if I wanted it to be 
> an enum? Too bad, C doesn't support that.

You can use a lambda:

```d
enum PI = () {
     mixin(C) {
         #include "pidef.h"
         return PI;
     }
}();
```

> What I'd like to see is:
>
> a) the C preprocessor is run on *all the mixin(C) islands of 
> the file* regardless of where they appear, whether they are in 
> templates, etc. Basically, take all the mixin(C) things and 
> concatenate them, run the result through the preprocessor, and 
> put the results back where they were. THEN run the importC 
> compiler on them. This allows a more cohesive C-like 
> experience, without having to import/define things over and 
> over.

Some downsides to this approach:

1. Concatenating all of the `mixin(C)` blocks in a module for 
preprocessing violates D's scoping rules and creates a lot of 
opportunities for "spooky action at a distance."
2. This would allow sharing macro definitions across `mixin(C)` 
blocks, but would *not* allow sharing declarations. You'd still 
have to `#include <stdio.h>` twice if you wanted to call `printf` 
in two different blocks, for example.
3. In order to "put the results back where they were" the D 
compiler would have to parse the preprocessor's output for [line 
markers][1]. Since the format of these is not specified by the C 
standard, this means the D compiler would have to have separate 
parsers for each C preprocessor implementation (or, at least, one 
for gcc/clang and one for MSVC).

[1]: https://gcc.gnu.org/onlinedocs/cpp/Preprocessor-Output.html


More information about the dip.ideas mailing list