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 [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
-~----------~----~----~----~------~----~------~--~---