From: Alexander Schofield Date: 2001-10-29T04:37:39+09:00 Subject: [ruby-talk:23691] Re: Ruby macros > Could you give some short examples showing the power of the CL macro system? Well, there is really no situation where a problem absolutely requires a macro solution as opposed to standard functions, but lest I get too abstract I should give a quick roundup of where they are most helpful, and where (at least in CL) they are most prevalent and why. Macros are often used to protect their arguments against evaluation, but also when you would like to have conditional, or repeated evaluation. But they aren't necessary for this, because you could just wrap up your args in a closure and use a function. I'll use an example from Paul Graham's, "On Lisp", where you have if as a function: (defun fnif (test then &optional else) (if test (funcall then) (if else (funcall else)))) and this would be called as: (fnif (rich) #'(lambda () (go-sailing)) #'(lambda () (rob-bank))) instead of the typical: (if (rich) (go-sailing) (rob-bank)) So macros aren't necessary for this, they just make things cleaner, just like you could use mapc (a function) instead of dolist (a macro): (dolist (b bananas) (peel b) (eat b)) (mapc #'(lambda (b) (peel b) (eat b)) bananas) What macros are really (for all practical purposes in CL) indispensible for is when you want to take apart argument forms, or bind variables passed in as arguments (why they are so useful for iteration constructs in particular). Take setq, a special operator in CL, used for assignment of a value to a symbol. But what if you want change a value in a list like so: (setq a '(1 2 3 4 5)) I want to change a from (1 2 3 4 5), to (1 15 3 4 5), if I use setq: (setq (cadr a) 15) I'll get some sort of error complaining that 2 is not a symbol (I've told it to assign 15 to 2), so what I need is the more generalized form of setq: the macro setf which will work fine on (cadr a). Basically setf sees if the first arg is a symbol, and if so it just expands to setq, but if it is instead a query it must expand into the corresponding assertion. The second part might be where macros appear most often. CL is full of them, in fact a great deal of CL is macros, which are built up on top of other macros and helper functions. Some of the notable examples are: *Most of CLOS *defun, used to define functions. *defmacro, used to define macros (don't ask) The most highly recommended book on macros would have to be Paul Grahams, "On Lisp", even though it slightly predates ANSI CL. But unless you can find it at a library you probably won't be able to obtain a copy since it is out of print. > Likewise for CLOS, could you give a short intro to what it is? My background is imperative programming languages and then pure functional ones but I've never used Lisp. CLOS is the, "Common Lisp Object System". Essentially it provides all the usual OO capabilities to Lisp (the one irritation is multiple-inheritence), but also adds a few quirks other systems have borrowed from to varying degrees. It's also a good example of an embedded language, and a posterchild for macros. Some of the aforementioned quirks are Auxilliary methods (before, after, and around methods augment the primary methods) which are more trouble then they're worth, method combination (in standard method combination, only the most specific primary method is called, but it can call others with call-next-method) which allows you to combine the results of all applicable primary methods and some other things like operator method combination. The most important thing to understand about CLOS is that it is (or at least CL advocates consider it to be) a different model of OO then the standard message passing model (Smalltalk, Ruby), the generic function model. In 1986 when Dynamic OO languages were the norm and statically typed OO languages were a curiosity, this distinction was more meaningful, but some of the concepts of CLOS have made their way down to conventional statically typed OOPLs. Basically the argument is that generic functions are a generalization of the message passing model, because in message passing you only specialize the first parameter (that is, the method name), but that in the generic function model you specialize the method for objects. This means that in a pure Generic Function model, methods do not belong to objects, but are specialized for objects, so in essence, a generic function is a function made up of one or more methods (note that you don't directly declare a generic function, you're doing that any time you declare a method). To Lispers in 1986, who might have had a good idea, but a only a vague notion of how to implement or conceive of it (especially when combined with lisp syntax having an unavoidable effect on them) this might have seemed natural. But the benefits (specialization of parameters) of the GF model are not inseperable from the GF model. What I'd like to see is the ability to specialize the parameters of a method *belonging* to an object in Ruby. This is more flexible than the method overloading of C++ and Java, because it is dynamic and optional. It does not in any way make Ruby statically typed (though you could think in those terms and use it as such) and what it essentially boils down to is syntactic sugar. Think back to every time you've had to manually check the type of an arg passed into a method, and had code branch depending on what type it was, and you have a problem which advocates this solution.