On 8/18/05, Logan, Patrick D patrick.d.logan@intel.com wrote:
In your opinion, is it appropriate to use a macro to abstract away repetitive boiler-plate code? Or is this better done in a procedure?
Two more places where a simple procedure won't do, but you have boilerplate code which calls for a macro are (both have occurred in my recent coding work on n-body integrators):
1. Various repetitive binding constructs i.e.:
(let ((m (body-m b)) (q (body-q b)) (p (body-p b)) (t (body-t b))) 'do-something)
becomes
(with-body (b) 'do-something)
This type of macro cannot be written with the syntax-rules defined in R5RS (there's no way to introduce the literal identifier 'm into the expansion of the macro), but can be written with the syntax-case extension (which is available in gambit), though it's easiest with define-macro:
(define-macro (with-body body . exprs) (let ((body-sim (car body))) `(let ((m (body-m ,body-sym)) (q (body-q ,body-sym)) (p (body-p ,body-sym)) (t (body-t ,body-sym))) ,@exprs)))
A fun exercise: convert this macro to (with-bodies (b1 b2 ...) ...) which does the above if called like (with-bodies (b) ...), but does
(let ((m1 (body-m b-one)) (m2 (body-m b-two)) (m3 (body-m b-three)) ...) 'do-something)
if called like (with-bodies (b-one b-two b-three ...) 'do-something).
2. Making little sub-languages for specialized processing e.g.
(with-vectors (v1 v2 v3) (v1 <- (+ v2 v3)))
for summing up the vectors v2 and v3 and storing it in v1. (I'm not going to put this macro up because it's long---the code is buried in this post: http://wmfarr.blogspot.com/2005/06/bigloo-macros-and-repl.html .)
#1 involves introducing new bindings into a section of code, and #2 involves changing the evaluation rules for a piece of code (the vector assignment is evaluated once for each index with the corresponding variables bound to elements of a vector). Procedures would not work for either of them; you have to have a macro.
My point is to illustrate just how nice it is to have macros in a language---and to encourage you to use macros to remove your boiler-plate code! These two macros have saved me literally thousands of lines of typing (and made my code clearer) over the past month, and they didn't even take very long to write.
Enjoy, Will