In Java, you often have to pair things, e.g. opening a file and closing it, to avoid leaking resources like file handles.
These pairings are among many cases where Java code contains structure that you can't extract and reify in your program. Macros make it possible to extract any such pattern, reify it, and call it. Instead of a recurring pattern of FileInputStream x = null; try { x = f.open(opts); doSomethingWith(x); } finally { if (x != null) x.close(); } you can convert all the crud into an abstraction and call it, like this: (with-open [x (.open f opts)] (do-something-with x)) All the constant stuff that would be repeated every time you open a file is gone; just which file, what options, what to call the stream temporarily, and what to do with the stream remains, along with the *fact* that you're opening some sort of a closeable stream and using it. Macros get you closer to the ideal of specifying every fact in exactly one place in your code. Here that fact is "how you ensure the file you open gets closed, including if an exception gets thrown while you're reading from it". In Java you have to tell the compiler how you do so over and over again at every I/O site; in Clojure you can tell the compiler how you do so once, calling this new abstraction with-open, and then at your I/O sites just tell the compiler with-open. In this instance, it's already done for you; with-open is part of core. In other instances you may spot a similar pattern of repetitive code but one that isn't already addressed in such a manner and then you can convert it into a callable abstraction yourself. The big decision point is: function or macro? In fact, the basic behavior of with-open could be implemented as a function: (defn with-open-fn [stream f] (try (f stream) (finally (.close stream)))) and called like so: (with-open-fn (.open some-file) #(do-something-with %)) The macro here just acts as syntactic sugar to let you avoid the #( ... % ...) closure around the body of code you want to run on the stream, and to let you name the stream something other than just %. In that sort of case it's good to have both the function and the macro; the macro can expand into a call to the function while having the nicer syntax. You absolutely *need* a macro if you need to control whether, when, and in what order arguments are evaluated (e.g. implementing flow control structures). (Interestingly, it's even possible to implement with-open's behavior as a Java method: public interface NullaryFn { Object doIt () throws Exception; } public interface UnaryFn { Object doIt (Object argument) throws Exception; } public class WithOpen { public static Object withOpen (NullaryFn streamMaker, UnaryFn fn) throws Exception { Stream x = null; try { x = (Stream)(streamMaker.doIt()); return fn.doIt(x); } finally { if (x) x.close(); } } } final File f = whatever; WithOpen.withOpen( new NullaryFn(){public doIt(){return f.open();}}, new UnaryFn(){public doIt(Object s){return doSomethingWith((Stream)s);}}); Look at that ugly call syntax, though. This is what you get because of a) Java lacking a decent syntax for closures, b) Java's strong typing (now you need casts everywhere; generics lets you get rid of that at the expense of having <T>s and <Stream>s everywhere instead), and c) Java's checked exceptions gimmick (now everything gets contaminated with "throws Exception;"). And your file related code is buried in just as much boilerplate junk as before, if not even more of it. Actually, the Clojure code turns into bytecode more or less equivalent to what you get with the above Java. (It actually wraps exceptions at function boundaries in RuntimeException instead of declaring throws Exception on every method; and you may need to type-hint the .open target to get a straight method call instead of a bunch of calls to the Reflection API; otherwise, more or less the same.) But the Clojure compiler lets you write closures with #(.open f) instead of new NullaryFn{blah, blah, blah} and have global callable entities like with-open that don't need a SomeClass. prefix tacked on, as well as leaving out all the type names, casts, and other nonsuch. And it lets *you* eliminate whole new classes of syntactic salt the compiler writers couldn't have known about, by writing your own macros that, in essence, extend the compiler. Any long repetitive structure of code that *can't* be made much nicer and still work properly by abstracting it into a function generally *can* be made much nicer and still work properly by abstracting it into a macro, and sometimes a macro can make things slightly nicer than a function (e.g., if the function will generally be called with an inline closure as one of its arguments, a macro with [other-args & body] parameters is good syntactic sugar to use, preferably writing the function and then making the macro emit a call to that function). -- 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 Note that posts from new members are moderated - please be patient with your first post. 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