As mentioned in the API for the define-macro function, it's very easy to write a macro that suffers from variable capture possibilities. Simply naming the arguments that the macro takes is the easiest way to shoot yourself in the foot, but even if you avoid that through the use of the 'args' function, hard-to-fix dangers still lurk.
From that discussion I've learned that the best way to write macros in newLISP is to:
- Use the default function to encapsulate them in their own namespace
- Use C-style naming conventions to avoid name conflicts with other contexts
Code: Select all
(define (def-static s body)
(def-new 'body (sym s s)))
(def-static 'my-or
(fn-macro (x y)
(let (temp (eval x)) (if temp temp (eval y)))))
(setq temp 5)
(my-or nil temp) => 5
Code: Select all
(define-macro (define-smacro _params)
(let (_newCtx (_params 0))
(eval-string (string (cons 'define-macro (cons (cons (sym _newCtx _newCtx) (rest _params)) $args))) _newCtx)
)
)
; usage:
(define-smacro (my-or x y)
(let (temp (eval x))
(if temp temp (eval y))))
The only problem so far is that in my tests using define-smacro was 11 times slower than the def-static function (repeated 10000 times). This makes sense because you have to build an expression, turn it into a string, and then evaluate that string. You can't use newLISP's eval function to do this because it won't place the arguments in the correct context.
Still, maybe this function might be useful to someone. It would be *really* nice if it could be included natively in the standard library as then it would be very efficient... (*nudge* *wink*) After all, why write unsafe macros when you could just as easily write safe ones? This would also give newLISP great bragging rights methinks. :-)