Hi folks,

I have been trying to work out how best to validate the structure of 
arguments passed into macros. It would appear that there are several 
ways of tackling this and I was wondering which is considered best 
practice. As an example, lets say I want a macro, 'print-even' which 
prints its arguments if they are even in number and throws an exception 
otherwise (sorry for the poor example but it's illustrative). I can see 
at least three implementations:

1) Defer all the work until the expanded macro code is executed:

(defmacro print-even [& args]
  `(if (even? (count '~args))
    (print ~...@args)
    (throw (Exception. "Uneven"))))

2) Perform the even? check at macro time, but leave throwing the 
exception until runtime:

(defmacro print-even [& args]
  (if (even? (count args))
    `(print ~...@args)
    `(throw (Exception. "Uneven"))))

3) Throw the exception at macro time:

(defmacro print-even [& args]
  (if (even? (count args))
    `(print ~...@args)
    (throw (Exception. (format "Uneven (%d arguments)" (count args)))))


Intuitively (3) feels like the right choice for two reasons:

- It does as much of the work as possible up front
- Given that defmacro is effectively extending the syntax of the 
language, you could view calling print-even with an odd number of 
arguments as a syntax error which seems best raised as early as possible

This has an obvious flaw though - the caller may expect to be able to 
supply an expression which they want evaluated:

(print-even (range 1 3))

With definition (3) this throws an 'Uneven' exception because we're 
counting the length of the unevaluated argument list. I suppose you 
could 'eval args' at macro time, but that may not always be wise :)

Presumably though it would be OK to (count args) at macro time if you 
didn't intend then to evaluate args in the print branch, which may 
result in a list of different length. Or is it considered bad form to 
throw exceptions at macro time, and hence definition (1) should always 
be used?

Best Regards,

Adam.


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to