Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is homoiconicity really needed for having macros?

2012-02-04 is sponsored by word "homoiconicity" http://en.wikipedia.org/wiki/Homoiconicity .

Background: I am about to choose which book about Clojure to buy -- either "Clojure in Action" or (incoming at the end of April) "Clojure Programming" (you can read it via O'Reilly Rough Cuts, half of the pages are visible). What struck me, that in both books this property -- homoiconicity -- got so much emphasis.

Since Clojure roots are Lisp-based, I referred "dead sexy" book is this really so big deal. Well, I can see macros explained in detail but I didn't catch the mentioned emphasis. Now compare to this (quote from "Clojure in Action")

This homoiconicity is also what makes Clojure’s macro system possible.

It almost looks like without it, macros wouldn't be possible. Even wikipedia statement (link above) is more balanced, but none of those sources (*) counts human factors in favour of English syntax.

If I am not mistaken, macro syntax (Lisp-like) could be possible in C# (for example), only with more effort from C# team. But it is cost of the designers team, not users (?). Second -- habbits matter. If in real life you think "a + b", and in computer world you constantly translate it to "+ a b", productivity suffer (I can see this for myself, when I went from C++ functors to C# lambdas).

This praise, that the Clojure programmer writes programs almost directly as AST, frightens me as reading that "thanks to writing the code directly in hex code, not only you learn hex system by heart, but you are closer to machine".

To sum up -- I love metaprogramming, I love Lisp-like macros (I am not a Lisper though), but I see two things here -- macros and homoiconicity. The first one is without a doubt great, the second -- not so much (as for my understanding), because it makes human fit computer needs, and it should be other way around.

The question

Is homoiconicity really so beneficial for humans (end users of language) or it is actually almost solely beneficial to language designers? Examples are very welcome!

Or just in case I rephrase -- assuming given language has Lisp-macros, will "adding" homoiconicity improve productivity of end-user? Expresiveness? Or quite contrary?

(*) I cannot be 100% sure, because I see only a fraction of Clojure books, and I am not reading them, just evaluating them for purchase.

Update

Thank you all for the answers, pity I had to pick only one as a solution :-), it does not mean I value others less, this one is most complete for me.

like image 665
greenoldman Avatar asked Feb 04 '12 20:02

greenoldman


People also ask

What is homoiconicity example?

Homoiconicity. Homoiconic languages typically include full support of syntactic macros, allowing the programmer to express transformations of programs in a concise way. Examples are the programming languages Clojure (a contemporary dialect of Lisp), Rebol (also its successor Red ), Refal, and more recently Julia .

What are the advantages of homoiconicity in programming languages?

One advantage of homoiconicity is that extending the language with new concepts typically becomes simpler, as data representing code can be passed between the meta and base layer of the program. The abstract syntax tree of a function may be composed and manipulated as a data structure in the meta layer, and then evaluated.

What makes a computer homoiconic?

All Von Neumann architecture systems, which includes the vast majority of general purpose computers today, can implicitly be described as homoiconic due to the way that raw machine code executes in memory, the data type being bytes in memory. However, this feature can also be abstracted to the programming language level.

What is a homoiconic language?

Homoiconic languages typically include full support of syntactic macros, allowing the programmer to express transformations of programs in a concise way.


1 Answers

Homoiconicity is not strictly required for macros (example: the C/C++ preprocessor implements a compile time macro system).

However homoiconcity makes macros much more effective and easy to use:

  • You avoid the need for a syntax parsing step: In a homoiconic language like Clojure, the source code can be directly used as the abstract syntax tree of the compiler. Less performance overhead for the compiler, less conceptual overhead for the user.
  • Code generation is easier - you just need to assemble the right data structure rather than carefully producing text source code in a form that can be successfully compiled. In general, textual code generation can be quite a tricky problem in languages that were not designed for it (you need to consider lots of things like symbol name generation, library imports, quoting rules, whether the compiler needs a source file to be written to disk etc.)
  • Your macro language is the same as your source language. No need to learn a separate language or set of constructs for macros.
  • IMHO homoiconicity makes macros much more simple, elegant and readable. In many cases, your macro ends up looking just like a template for the correct code.

As a small example, here's a macro that adds a Java/C# style "for" loop to Clojure.

(defmacro for-loop [[sym init check change :as params] & steps]
 `(loop [~sym ~init value# nil]
    (if ~check
      (let [new-value# (do ~@steps)]
        (recur ~change new-value#))
      value#)))

;; Usage:
(for-loop [i 0 (< i 10) (inc i)] 
  (println i))

And that's it - a new language construct added in six lines of code. You can see the homoiconicity clearly in action - the whole "loop" form is just a quoted Clojure data structure. The init, check and change parameters are also homoiconic clojure data structures passed to the macro that represent the loop control expressions. There was no need to do any parsing to support my new syntax.

I think it would be very hard to do this as concisely or simply in any non-homoiconic language.

like image 163
mikera Avatar answered Nov 09 '22 01:11

mikera