From: Brian Marick Date: 2001-08-07T02:21:15+09:00 Subject: [ruby-talk:19236] Lisp macros (was: Re: Ruby as opposed to Python?) At 04:50 AM 7/24/01 , HarryO wrote: >Seriously, though, he mentions as one of the big features they used in >their development was the ability to define macros. Not knowing anything >much about LISP, I was wondering whether you can tell me whether ruby's >eval (perhaps along with otherruby features) can be used to achieve the >same functionality as LISP's macros, or are they more complex beasts than >that? Ie, do they provide something we're missing out on? I'm not sure the question was answered in a way clear to someone who doesn't know what Lisp macros are, so let me take a shot. Disclaimer: I haven't coded in Common Lisp since '85 or so, and I don't know anything about the new crop of functional languages. What's nice about Lisp macros is that they let you extend the language within the language, instead of by messing with the underlying implementation. Here's how it works. Suppose your version of lisp only has "if", which looks like this: (if test then-case else-case) You decide you'd like an "unless". It would help you make your code clearer. You can't make it a function (defun unless (test then-case else-case)...) because both the "then" and "else" arguments would be evaluated whenever it was called. Were it not for macros, you'd be stuck. But you can define a macro, which looks like this: (defmacro unless (test then-case else-case) `(if (not ,test) ,then-case ,else-case)) (The quoting works roughly like Ruby's #{} inside of strings.) Now you can scatter unless's throughout your code. Whenever the interpreter sees one, it executes the macro, then executes the if-expression that the macro expands out to. The difference between a macro and eval is that a macro can change the syntax of the language (provided that the language always stays parenthetical). That seems to lead to faster language evolution. For example, people always used lists like structures or records. There are lots of old lisp programs where the programmer just remembered that the third entry in a Person list was the address. They were kind of hard to read. So people started defining accessor functions: (defun name(person) (car person)) (defun phone(person) (cadr person)) (defun address(person) (caddr person)) That's kind of boring, so (I imagine, though I wasn't there) people started inventing macros like this: (defstruct person name phone address) That macro creates functions "make-person", "person-name", etc. Over time, people converged on a standard defstruct, and the compiler writers could take hold and build it into the language in a more efficient way. Now, faster language evolution isn't necessarily a good thing, and community development of a language isn't necessarily better for the language than the Linus / matz / Larry Wall "benevolent gatekeeper" approach. But it's that kind of power that I think Graham was talking about. It really is quite nice to be able to tweak the language to fit the way you think about the problem. I didn't find it made other people's code hard to read - it's hard to say 16 years later, but people seemed to share conventions for how to do things and those conventions were easy to pick up. -- Brian Marick, marick@testing.com www.testing.com - Software testing services and resources www.testingcraft.com - Where software testers exchange techniques www.visibleworkings.com - Adequate understanding of system internals