
Paul Mensonides wrote:
I'll reiterate something that you said a while back (paraphrasing). The greatest harm that the macro mechanism (in C/C++) has caused is that it has kept people from realizing the benefits of syntactic abstraction.
Furthermore, whether something is or isn't a macro is irrelevant. It is whether it provides a useful abstraction that is documentable. As a macro, the name is not going to collide with anything because of all-caps and the BOOST_ prefix. Similarly, it isn't going to accidentally expand in any code. As I've said before (paraphrasing), macro invocations are nothing like function calls except in appearance, and nearly all other macro-related problems stem from developers viewing them as if they are. Macros' "return values" are code snippets, not values. E.g.
#define max(a, b) ((a) < (b) ? (b) : (a))
The problem here is not that 'max' has a problem with multiple evaluation; the problem is that typical developers view 'max' as returning either 'a' or 'b'. In other words, whether an abstraction is a macro is an important documentation point, and the documentation of an abstraction, regardless of what it is (macro, function, class, etc.), dictates the entirety of how it is to be used.
Agreed. In the case of max, it's the syntactic similarity with a function call that lures people into making certain assumptions. Same goes about non-macro entities such as auto_ptr - "a = b;" looks like something that ain't. By the way, it was FOREACH that inspired me to figure out a simple solution to max, which then Eric improved. It's basically like this: #define max(a, b) (max_fn(true ? (a) : (b), false ? (a) : (b))) which presto, nice-o passes the appropriate types to a template max_fn function that now can be smart about returning lvalues and so on. Andrei