On Tue, Dec 23, 2008 at 10:15 AM, Adam Harrison (Clojure) <adam-cloj...@antispin.org> wrote: > > 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 :)
But definition (1) throws that exception as well, because you are (correctly!) supplying 'count' with the unevalutated seq provided by 'args'. It seems to me you were suggesting two different potential requirements: (A) an even number of args, and (B) a (single?) expression that returns a collection with an even number of items. For (A) I agree that (3) seems like the best option. Why delay until runtime the reporting of an error that at compile time you know exists? For (B) as you say the only way to get the error at compile time is to eval the args -- and is that still compile time? Anyway, I'd agree that for (B) something like option (1) (but without the quoted args) would be the best. > Or is it considered bad form to throw exceptions at macro time, and > hence definition (1) should always be used? No, exceptions from macros are fine. I believe they usually even end up at the Repl with the file and line number where the macro was being used. --Chouser --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---