Macros, like the goto statement, have become somewhat frowned upon nowadays, but (IMO) I think that’s a little excessive. Macros used correctly, within the confines of symbol declaration (i.e. no computation), can be beneficial.
For example, you may want code to execute in debug but not release, you can define the symbol accordingly and avoid hundreds of #ifdef’s throughout your codebase. Arguably, you could achieve the same effect with a Null Object, but not as simply.
Recently, I was going through some of my old code and found a (pre-modern C++) client ORM I had written which leveraged macros as a DSL. You essentially use the macros to declare your entities, classes and queries in a header file and the compiler generates the appropriate code. It’s pretty basic, and doesn’t support aggregation, but was sufficient for our needs at the time.
Note: Please overlook the fact I’m prefixing symbols with double underscores, I didn’t know at the time that was reserved for the compiler’s internal usage.
Here is an example .h file declaration:
That’s it, you just declare it and use it like so:
The table comes with basic CRUD functions, but here’s an example of extending it via macros:
And an example using the generated select function:
Now for the macro magic which generates the code behind the scenes:
(note this is all on one line, formatted here for readability)
The function the above macro depends upon to do it’s work:
In general, the advice to avoid macros is wise. There are known pitfalls, with unexpected side-effects; and debugging can get frustrating when you’re looking at ‘Ghost Code’. But still, they are just another tool that can be put to good use in some cases when applied carefully and sparingly.
I’m limiting myself to symbol declaration only. Typically issues with macros occur when they are used for computations, or they operate on their arguments – in which case it is better to use templates. It’s worth noting that quality C++ frameworks like Qt use macros extensively.
Interestingly, for Pascal developers, the Free Pascal Compiler has its own implementation of macros – see here. Whilst Delphi has avoided them altogether.
In my opinion, macros aren’t completely bad 🙂