3 ms·
> a certain C macro might evaluate some expression twice. Everyone knows that this is dangerous...ISO C itself says that getc may evaluate its argument multiple
by mschaef 10y ago
> a certain C macro might evaluate some expression twice. Everyone knows that this is dangerous...ISO C itself says that getc may evaluate its argument multiple times; ... Lisp macros do not have issues that are unfixable in this way.
If your macros is 'fixed' to emulate function call semantics by evaluating its arguments only once, then maybe a function is a more appropriate abstraction in the first place. The whole point of macros is that they let you break the rules of function call application in hopefully useful and predictable ways.
Another way to look at it is that repeatedly evaluating an argument is what you do NOT want for a macro like 'getc', but probably what you DO want for a macro like 'repeat'. The danger lies in the fact that it's hard to tell the difference when looking at a call site in isolation.
Whether or not that danger is an acceptable risk is, of course, situation dependent.
- kazinator 10y agoBy the way, some 18 years ago, I came up with a system for catching the use of expressions with side effects in C macros. Basically, I introduced an API that you could use in your macro definitions to identify insertions of expressions which would cause problems if containing side effects. This API, at run-time, would parse the expressions, analyze them for side effects, and diagnose problems. (It would also cache the results for faster execution of the same macro site.) All the programmer has to do is achieve run-time coverage to catch all the problems. We could define a getc-like macro such that getc(*stream++) would diagnose, provided that the line is executed. See sfx.h and sfx.c here: http://git.savannah.nongnu.org/cgit/kazlib.git/tree/ http://git.savannah.nongnu.org/cgit/kazlib.git/tree/
- kazinator 10y agoThere are all kinds of macros that have to evaluate an expression exactly once, and cannot be made into functions. ;; cond evaluated exactly once; ;; then or else at most once, not before cond. (if cond then else) getc doesn't have to be a macro. It illustrates just the point that the macro issues in C are so unfixable that broken macros have even been codified in ISO C.
- mschaef 10y agoSure, functions can do that and more (borrowing a page from Smalltalk): (if* cond #'(lambda () then) #'(lambda () else)) All the macro does is eliminate the need to write out all the lambda syntax. (defmacro (if cond then else) `(if* ,cond #'(lambda () ,then) #'(lambda () ,else))) This brings my back to my original point: "the extent of the logic encoded in macros should be minimized, with the macros translating the code pretty much straight away into something built on more functional abstractions.". Works in C too, although not as nicely: void dscwritef_impl(const _TCHAR * format_str, ...); #define pdscwritef(flag, args) \ do { if (DEBUG_FLAG(flag)) dscwritef_impl args; } while(0); The funny thing is, I think we're largely in agreement.
- kazinator 10y agoI do not agree that an if macro stands for some specific lambda-based utterance. That isn't historically true, or in any other sense. The macro potentially stands for any and every possible way in which its semantics can be achieved.
- mschaef 10y ago> I do not agree that an if macro stands for some specific lambda-based utterance. That isn't historically true, or in any other sense. Huh? Are you saying the use of lambdas does NOT give if* the ability to control the execution of 'then' and 'else'? My point is that if you're concerned about how often you evaluate a block of code (0, 1, or n times), there are ways to achieve this goal that do not require macros. (And consequently, the macros mainly serve as they should: to clean up the syntax, if necessary.)
- kazinator 10y agoI never wrote that macros are required to control evaluation. Rather, what I wrote is that there are examples of macros for which evaluation is specified. In fact, most ANSI Lisp macros are like this; unless stated otherwise, those constituents of a macro call which are forms are evaluated once, and left to right. The whole point is that this sort thing can be specified, because there is a robust way to write macros to meet the specification. I gave if as an example; it was not intended to be an example of a macro which has to go out of its way to ensure once-only evaluation. There are common examples of macros that use machine-generated unique variables to hold the results of evaluating an argument form, in order to be able to insert that value into multiple places in the generated code. An implementation of with-slots likely has to, for instance. In documenting a library of C macros, we cannot specify a strict evaluation order without seriously constraining which of those macros are actually implementable.