News for hackers. Stuff that matters.
Re:Macros on Steroids: How pure C can benefit from metaprogr... by gsmecher on Thursday July 22, 2021 @11:55AM (#27920384)
There are good reasons to reach for macro libraries. They're rare, but they're out there. I make heavy use of boost::preprocessor in a C project and it was fundamentally enabling. I have occasionally cursed at it but never regretted it.

It is basically impossible to provide a "kind" development environment using deep macro trickery. The error messages you get from this kind of library are a major handicap. This failing is intrinsic to the landscape and not something you can really fix.

Historically, macro processors in major compilers were inconsistent, limited, and arbitrary, making heavy macro use frustrating, limited, non-portable. I think this is mostly historical now.

IMO people should prefer boost::preprocessor for purposes like this (even in pure C), since it is battle-tested and more polished than "little" metaprogramming libraries will likely ever be. (This is advice to possible users, and not a knock on the author. Props for exploring the space and building something useful.)

Re:Macros on Steroids: How pure C can benefit from metaprogr... by Hirrolot on Thursday July 22, 2021 @12:25PM (#27920879)
> IMO people should prefer boost::preprocessor for purposes like this (even in pure C), since it is battle-tested and more polished than "little" metaprogramming libraries will likely ever be.

In fact, I used to program in boost::preprocessor before, trying to implement ADTs [1]. At the end of the game, I just realised I didn't have enough patience and whatever else to continue using it. I could accidentally see that some macro got blocked and then debugging it for a half of a day to eventually come up with ugly workarounds.

Then I made Metalang99. It has many neat features but really the very motivation for it was to get rid of macro recursion blocking. For example, if you call FOO, then FOO calls BAR, BAR calls JAR, and JAR calls FOO, everything should work as expected. This was a complete nightmare with boost::preprocessor.

So in conclusion, I agree that boost::preprocessor is more polished and can work on ancient compilers too. However, since nowadays the situation with preprocessors is better, I would endeavour to use more modern tools which offer greater convenience and flexibility.

[1]: https://github.com/Hirrolot/poica

Re:Macros on Steroids: How pure C can benefit from metaprogr... by gsmecher on Thursday July 22, 2021 @12:43PM (#27921153)
You're absolutely correct, boost::preprocessor has an obligation towards backwards compatibility that independent efforts do not. This obligation is a double-edged sword: when I pick a library, I want it to be modern; 5 years later, I shouldn't be forced to refactor my code to match a library update. There's a good parallel here with boost::python vs. pybind11; there's always room for more and newer entrants, but most of them will not overcome the first-mover advantage.

On the boost front, I should have noted the difference between VMD [1] and boost::preprocessor [2]. I think VMD [1] trades some backwards compatibility for coherence and consistency and is a better starting point for new code.

[1]: https://www.boost.org/doc/libs/1_70_0/libs/vmd/doc/html/inde...

[2]: https://www.boost.org/doc/libs/1_76_0/libs/preprocessor/doc/...

Re:Macros on Steroids: How pure C can benefit from metaprogr... by ska on Thursday July 22, 2021 @02:56PM (#27922793)
> It is basically impossible to provide a "kind" development environment using deep macro trickery.

Unless it's in a language actually designed for meta-programming. Obviously if you are already in a C project this might not be practical, but if you need a lot of it you may just be using the wrong tool for the job.

Re:Macros on Steroids: How pure C can benefit from metaprogr... by gsmecher on Thursday July 22, 2021 @03:39PM (#27923245)
I was specifically commenting on cpp-style macros. Apologies if this was unclear.
Re:Macros on Steroids: How pure C can benefit from metaprogr... by nicoburns on Thursday July 22, 2021 @12:34PM (#27921019)
If you need these kinds of advanced metaprogramming capabilities then I feel like that's a sign that maybe plain C isn't suitable for your project and you'd better off switching to Zig, Rust, D or C++. These all provide powerful compile-time execution capabilities and the ability to expose C interfaces.
Re:Macros on Steroids: How pure C can benefit from metaprogr... by lhorie on Thursday July 22, 2021 @12:54PM (#27921308)
Even those may not be powerful enough. I have a use case where I was trying to read specification files to generate unicode tables. But using something like zig's @embedFile to get a handle to a []u8 in a comptime block doesn't work because I don't want the file to be embedded into the binary; I want something more akin to turing complete code generation. And I don't need it to run it on every compile, as the entire flow involves downloading said files off the internet, but only when a new version of the spec is released. I ended up just using code generation.
Re:Macros on Steroids: How pure C can benefit from metaprogr... by samatman on Thursday July 22, 2021 @03:31PM (#27923155)
Zig is a work in progress, and I bet the community is interested in supporting this sort of use case.

Might be nice to bring it to their attention, if you haven't already, and if you have the time and inclination.

Re:Macros on Steroids: How pure C can benefit from metaprogr... by kaba0 on Friday July 23, 2021 @02:33AM (#27927837)
I think at this point it should rather be part of the build process. No program build itself should download files in an ad hoc manner.
Re:Macros on Steroids: How pure C can benefit from metaprogr... by Hirrolot on Thursday July 22, 2021 @12:39PM (#27921095)
Only if you can switch to something like Zig, Rust, etc. But a tremendous amount of code bases are already written in plain C. Using preprocessor metaprogramming allows you to invoke macros right in the same files in which you write ordinary C code, without the need for integration with other languages.
Re:Macros on Steroids: How pure C can benefit from metaprogr... by nicoburns on Thursday July 22, 2021 @12:47PM (#27921223)
> Using preprocessor metaprogramming allows you to invoke macros right in the same files in which you write ordinary C code

C++ effectively lets you do this too. And Zig will let you import and compile C files seamlessly. I suppose you have to switch compilers, but that's not so different to adding the additional pre-processor compiler.

Re:Macros on Steroids: How pure C can benefit from metaprogr... by Hirrolot on Thursday July 22, 2021 @01:04PM (#27921456)
C++ can, fair. Still there is a huge amount of developers sticking to plain C, even if they can use C++ (FFmpeg, VLC, Linux, etc.), why do they do that? I think an answer to this question would be pretty much the answer for the initial question. There might be cultural, historical, and other reasons for it.

The thing with Zig is that, if I understand it correctly, Zig can't be interleaved with other C code in the same file, which forces you to separate things, loosing convenience. On the other hand, to use Datatype99, you can just #include <datatype99.h> and you're ready to go.

Re:Macros on Steroids: How pure C can benefit from metaprogr... by gsmecher on Thursday July 22, 2021 @12:54PM (#27921301)
To date, C's most proximate (management-friendly, technically similar, programmer-skill-adjacent) competition has been c++. (I'm trying to lay the groundwork for the next statement: I'm not claiming this is good, and excited to see Rust and friends as serious contenders. Stay with me.)

Even in c++20, there are things you can do with macros you can't do in the language. This may change when reflection lands in c++2x, but I won't be able to use it for years and widespread adoption won't be possible for another decade.

Re:Macros on Steroids: How pure C can benefit from metaprogr... by spaetzleesser on Thursday July 22, 2021 @04:19PM (#27923806)
When I look at a lot of things that are done with reflection in C# I personally would much prefer the preprocessor and macros. Things that could be done in a type safe manner with a macro in a few lines become way more complex when using reflection.
Re:Macros on Steroids: How pure C can benefit from metaprogr... by mumblemumble on Thursday July 22, 2021 @04:46PM (#27924094)
Could I beg of you to give an example?

Back when I was working in C#, there were quite a few times when I'd encounter things being done with reflection that I wish had been done with less code and a more type safe manner by just... not using reflection. I always just assumed a lot of that was just bad habits left over from the .NET 1.0 days, back before generics. So I'm curious if there's much overlap there? If it's only a subset, I don't know C as well as I'd like, so it would be interesting to see something that the C preprocessor handles better.

Re:Macros on Steroids: How pure C can benefit from metaprogr... by spaetzleesser on Thursday July 22, 2021 @10:08PM (#27926477)
For example INotifyPropertyChanged which is used in WPF.

The typical implementation is something like this:

     public string CustomerName  
        {  
            get  
            {  
                return this.customerNameValue;  
            }  

            set  
            {  
                if (value != this.customerNameValue)  
                {  
                    this.customerNameValue = value;  
                    NotifyPropertyChanged();  
                }  
            }  
        }  

When you have 20 properties you have a ton of repetitive code. With a preprocessor I could reduce each property to a one liner. You can also do tricks with reflection but that's way more complex to implement.
Re:Macros on Steroids: How pure C can benefit from metaprogr... by mumblemumble on Friday July 23, 2021 @09:13AM (#27930264)
Yeah, there is that, but I wash hoping to see a great use case for C preprocessor macros. WPF data binding doesn't seem like good candidate for something you're likely to want to do in a C program.

Or were you really just meaning to advocate for metaprogramming in general?

Re:Macros on Steroids: How pure C can benefit from metaprogr... by gsmecher on Friday July 23, 2021 @01:26PM (#27933312)
I design instrumentation for telescopes, in which C code on an embedded processor peeks and pokes device registers on an nearby FPGA. This C code forms an interface between hardware and the network.

In this system, I write a given function in C and surround it with a macro wrapper. This wrapper generates a JSON-RPC equivalent of the C function using the Jansson JSON library [1], complete with argument typechecking and error management. My C code can call the function normally, and an embedded webserver [2] can export it across the network where it's used fairly transparently by a Python stack on a control PC.

All three of these "embedded software" elements (the embedded webserver, the JSON library, and the FPGA interface) are very well suited to C. I have recently dabbled in moving parts of it to C++, and have found a few surprising impedance mismatches. (As I mentioned above, C++ still lacks reflection.)

The macros, here, are not for "elegance" or any other abstract purpose. They have allowed a ~80% reduction in boilerplate and an equally impressive reduction in the bugs and hassles associated with this kind of low-density, high-sprawl code.

[1]: https://digip.org/jansson/

[2]: https://www.gnu.org/software/libmicrohttpd

Re:Macros on Steroids: How pure C can benefit from metaprogr... by touisteur on Thursday July 22, 2021 @05:03PM (#27924304)
I'm a huge fan of java because of reflection. It can be so empowering and awesome. But lately I've come to prefer codegen+JIT when possible. So, discovery through introspection, and to call/read/modify stuff I'll generate the code.
Re:Macros on Steroids: How pure C can benefit from metaprogr... by Zababa on Thursday July 22, 2021 @01:57PM (#27922134)
If you want ADTs and can afford the (slight) performance hit and the higher resource consumption, you can even look into OCaml.