Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am new to learning Clojure. I started couple of months ago. I am trying to learn Macros.

I initially got confused understanding difference between macros and higher-order functions in Clojure as a higher order function could take lambdas and execute one of them how many times it wanted based on any conditions and filter.

So I posted a question with a simple example regarding this on StackOverflow itself. I got my doubts cleared from the answer.

This is what I understood,

  • Macros won't evaluate all the arguments unlike functions to evaluate the body.
  • Macros can be selective about what to evaluate and what not and how to convert one piece of code into another using quote,unquote and splicing syntax.
  • The final code that comes out of the macro is then evaluated.

So my question is, How is it different from preprocessor directives and macros used in C ? What power does Lisp/Clojure macros give to the developers which C macros completely lack and are often used widely.

share|improve this question

3 Answers

up vote 11 down vote accepted

Some notable differences:

  • Clojure macros operate on Lisp data structures whereas C macros operate on text. This capability is a consequence of Lisps being homoiconic (i.e. Lisp source code is expressed as Lisp data structures). Homoiconicity isn't strictly necessary for a macro system to be effective, but it certainly makes it much more convenient and natural.
  • You can execute Clojure macros at runtime as well as compile time (e.g. using eval)
  • Clojure macros are written in Clojure itself. Contrast with C preprocessor macros, which have their own separate mini-language. This is a big advantage when writing more complex macros: you don't have to mentally switch between different languages (you do of course still need to mentally distinguish between which code you want to execute while processing the macro vs. which code you want to generate as the output of the macro)
  • Clojure macros are Turing complete - you can perform arbitrary code generation within them. Not true for standard C preprocessor macros, which are somewhat limited in their ability to express complex code generation. EDIT: Thanks Jeremy for providing links to some amusing hacks by which the C preprocessor can be coerced into acting in a turning-complete manner. The overall point still stands though: these aren't really practical ways to write general purpose code.

Arguably, macros are still the distinguishing "killer feature" of Lisps. For a little extra explanation on this topic, it's worth reading Paul Graham's essay "What Made Lisp Different"

share|improve this answer
3  
Actually, you can have a full macro system without homoiconicity. The data structures used to represent code just have a more complex shape than Lisp data structures. See for example Scala macros. – Jeremy W. Sherman Jul 8 at 14:34
Also, the C preprocessor is arguably Turing complete: "… the preprocessor can act as a Turing complete language, but instead of being limited to the finite memory of a computer it is instead limited by the finite number of scans applied." See also Daniel Holden's reflections following his writing a Brainfuck interpreter purely using cpp. – Jeremy W. Sherman Jul 8 at 14:37
1  
Another thing that is a consequence of your listed properties, but that should be listed as a separate point, is that with Clojure macros it is easy to create new control structures (conditional forms, loops, with-... forms etc) which can then be used using normal Clojure syntax. – Terje D. Jul 8 at 18:09
@JeremyW.Sherman You might consider C macros Turing complete, but it's still not possible to do arbitrary transformations with them (even if you do as many passes as you want), which I think is the more important point. For example you can't write a macro M, such that M(f(x)) expands to f(x,y) or g(x). – sepp2k Jul 8 at 18:17
@sepp2k Aye, but too often folks hold up Turing completeness like some high bar. There are a large number of really ugly low-level languages that purposefully or semi-accidentally exhibit Turing completeness. Being a practical general-purpose programming language is a completely different matter. :) – Jeremy W. Sherman Jul 9 at 4:05

C macros allow plain text substitution and are pretty dumb(in terms of operations that can be performed). Further, if it did allow more complicated expressions, using it would be cumbersome because you're manipulating plain strings.

Since Clojure and Lisps in general use S-Expressions(which are just plain linked lists) and allow the full language to be used at macro-expansion time, you can build far more complex and useful expressions.

share|improve this answer

C macros are purely textual rewriting macros. There's nothing terribly C about them aside from that being where they came from – you can use the C preprocessor cpp(1) on any text. Consequently, it's easy to generate non-C forms using the C preprocessor, and you often have to jump through hoops to do fairly trivial things as far as C itself goes. C macros are full of pitfalls because of this.

Clojure macros are Clojure code that executes using a different set of rules than regular Clojure functions. Instead of receiving evaluated arguments and returning a result, they receive unevaluated forms and return a form, which might eventually be evaluated during the course of normal execution.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.