From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: pjb@informatimago.com (Pascal J. Bourguignon) Newsgroups: gmane.emacs.help Subject: Re: Is it possible for a macro to expand to nothing? Date: Tue, 24 Nov 2009 12:14:50 +0100 Organization: Informatimago Message-ID: <87ljhwb2dx.fsf@galatea.local> References: <87vdh1ccra.fsf@galatea.local> <87my2dc8d7.fsf@galatea.local> <873a44dcf2.fsf@galatea.local> <87pr78b6n9.fsf@galatea.local> NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: ger.gmane.org 1259062996 19062 80.91.229.12 (24 Nov 2009 11:43:16 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Tue, 24 Nov 2009 11:43:16 +0000 (UTC) To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Tue Nov 24 12:43:09 2009 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([199.232.76.165]) by lo.gmane.org with esmtp (Exim 4.50) id 1NCtnY-0004Tu-IA for geh-help-gnu-emacs@m.gmane.org; Tue, 24 Nov 2009 12:43:08 +0100 Original-Received: from localhost ([127.0.0.1]:48178 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NCtnX-000761-CW for geh-help-gnu-emacs@m.gmane.org; Tue, 24 Nov 2009 06:43:07 -0500 Original-Path: news.stanford.edu!usenet.stanford.edu!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail Original-Newsgroups: gnu.emacs.help Original-Lines: 238 Original-X-Trace: individual.net JKu+wl+Fi+sOGvp5JSKXDwFGKutBlkwtP96HbAzYI7Kkmhot6M Cancel-Lock: sha1:ZmE5NzYxNTQwNmNlM2MzODYxN2Q0M2ZmZDU3YzBiMmJhN2Y4ZGUzNw== sha1:/ofPrOxCFUkdVK+CV4Fr7YlY5hE= Face: iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAQMAAABtzGvEAAAABlBMVEUAAAD///+l2Z/dAAAA oElEQVR4nK3OsRHCMAwF0O8YQufUNIQRGIAja9CxSA55AxZgFO4coMgYrEDDQZWPIlNAjwq9 033pbOBPtbXuB6PKNBn5gZkhGa86Z4x2wE67O+06WxGD/HCOGR0deY3f9Ijwwt7rNGNf6Oac l/GuZTF1wFGKiYYHKSFAkjIo1b6sCYS1sVmFhhhahKQssRjRT90ITWUk6vvK3RsPGs+M1RuR mV+hO/VvFAAAAABJRU5ErkJggg== X-Accept-Language: fr, es, en X-Disabled: X-No-Archive: no User-Agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/22.3 (darwin) Original-Xref: news.stanford.edu gnu.emacs.help:175012 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:70083 Archived-At: Alan Mackenzie writes: > Pascal J. Bourguignon wrote: >> Alan Mackenzie writes: > >>> Pascal J. Bourguignon wrote: >>>> "Drew Adams" writes: > >>>> This is the problem! Macros shouldn't return a _list_, they should >>>> return a _form_. If you write a macro that returns a list, or you >>>> use it so that it returns a list, that is not a valid form, then it >>>> is not good style, even if you catch up. > >>> Is that right? I think you should be required to justify this >>> assertion of "good style". If that "good style" really is good style, >>> then the whole of cc-langs.el (which uses intense macro magic to >>> generate data structures with both compile-time and run-time >>> behaviour) is attrocious style. > >> If that was the case, yes, I would think so. Macros are designed to >> generate code, not other data. > > I'm no lisp guru, but I must disagree strongly with this. What is code, > what is data? Surely they are essentiallty the same, particularly in > lisp. You would hold that a macro which generates a font-lock-defaults > structure (so as to reduce the tedium of doing it by hand) is an abuse of > the macro idea, would you? There is an essential difference between "code" and "data". I won't define data, let's take it as axiom. Code is a kind of data, for which there exist a processor. Of course, you can always produce a processor to handle any kind of data: (defun data-processor (data) data) Lisp code is the kind of data that is accepted by eval. Valid lisp code is the kind of lisp code that eval can process and return the result without signaling an error (it can signal errors internally, if they are caught). Valid Zorblug code is Zorblug code that zorbluyg can process and return the result without signaling an error. (defun zorblug (form) (if (listp form) (apply (function +) (mapcar (function zorblug) form)) (error "Not a zorblug form %S" form))) (zorblug 42) --> Debugger entered--Lisp error: (error "Not a zorblug form 42") (zorblug '(nil (nil nil) nil)) --> 0 data valid Zorblug code Lisp code Valid lisp code 42 yes no yes yes (nil) yes yes yes no (+ 1 2) yes no yes yes (/ 1 0) yes no yes no My claim is that it is not a good style to write a macro that produces non valid lisp code, because lisp macros are designed to produce code that will be evaluated by the lisp eval, not by the zorblug processor or any other random data processor. (There may be an exception, where a macro generate lisp code that signal an error, if this is the specific purpose of the macro; but for a normal macro, it is better if it generates only valid lisp code). If you want to transform code for other processors, or random data, use functions. Notice that the above data-processor doesn't use lisp macros. You could try to hook lisp macros in the data-processor, but this would be bad style, and it would probably be easier and safer (namespace wise) to just write your own data macro system, since implementing one is rather trivial. >> If you are generating general data, then using functions will be easier >> and clearer. > > If it's possible. But if this were the case, using functions to generate > "code" would be easier and clearer, too. Absolutely. And more useful in some circumstances too. That's why you should write non trivial macros as a mere call to the code generating function: (defmacro non-trivial-macro (arguments...) (generate-non-trivial-code arguments...)) >> But cc-langs.el only defines four macros and they all generate >> perfectly good lisp code. > > Any macro, once debugged, generates "perfectly good" lisp code. I don't > understand where this notion of "perfectly good" comes from. It means valid lisp code, see definition above. >>> Fact is, though, it allows a simple tabular writing of constants which >>> vary between C, C++, java, .... Kudos to Martin Stjernholm, who wrote >>> it. > >> Unfortunately, most of emacs lisp code is bad code. Functions one >> kilometer long, chained with one or more others one kilometer long. >> Copy-and-pasted chunks instead of abstracting it away. Etc. > > I can't disagree with that, sadly. However I think Emacs's code base is > better than a typical 25 yo application still under development (if there > is such a beast). Yes, the fact that it still runs, is still useful, and can still be maintained despite these bad parts is proof of it, that it's better than typical 25 yo or even a lot of much younger programs. >> Now of course, I had a peek at code that had bugs or missing features >> in the first place. Perhaps the good quality emacs lisp code I hadn't >> a peek at because it worked well enough so I didn't need to. > > Perhaps. > >>>> Because it is a better style. It avoids abusing the ifdef macro. > >>> Where does this notion of "abuse" come from? What is its rationale? >>> (This is a genuine question.) > >> The general contract of a macro is that it returns valid forms. > > Sorry, Pascal, you're just restating the same thing again, not answering > my question. Why should I accept this "general contract of a macro"? I > haven't signed it. ;-) Is there some respected Lisp guru who says this? It comes directly from the definition of defmacro, defmacro is a special form in `src/eval.c'. (defmacro name arglist [docstring] [decl] body...) Define name as a macro. The actual definition looks like (macro lambda arglist [docstring] [decl] body...). When the macro is called, as in (name ARGS...), the function (lambda arglist body...) is applied to the list ARGS... as it appears in the expression, and the result should be a form to be evaluated instead of the original. (for the definition of form, see the Common Lisp glossary entry I quoted elsewhere in this thread). > What would this guru say about the macro which generates a > font-lock-defaults structure? If this structure cannot be passed to eval without signaling an error, then I would say that it is bad style to use a macro to generate such data. >> In all fairness, ifdef does return valid forms, when provided valid >> forms as argument. > >> (defmacro ifdef (expr &rest body) >> (and (eval expr) `(progn ,@body))) > > That version of ifdef is ugly because it contains an obtrusive `progn'. In a way here, progn is the dual of list. When you want to generate a list of data, you use list: `(list ,expr1 ,expr2 ... ,exprN) When you want to generate a list of code, you use progn: `(progn ,form1 ,form2 ... ,formN) It is not obtrusive in any way, it only shows that we are generating code, not mere data. > The version I used doesn't. There is no guarantee that a lisp compiler, > particularly the Emacs lisp byte compiler, is going to optimise away this > unnecessary artifact. All lisp compilers will obviously optimize out embedded progn forms, because no object code can correspond to it. (disassemble (byte-compile '(lambda () (progn (progn (progn) (progn)) (progn))))) --> byte code: args: nil 0 constant nil 1 return They would optimize out similarly unneeded forms: (disassemble (byte-compile '(lambda () nil nil nil nil nil))) produces the same byte code as above. > It seems this `progn' is there purely to satisfy > the (as yet unsubstantiated) injunction to return only "perfectly good" > lisp forms. Not 'purely'. You could optimize it out when unnecessary with: (defun progn-encapsulate (forms) (if (= 1 (length forms)) (first forms) (list* 'progn forms))) (defmacro ifdef (expr &rest body) (and (eval expr) (progn-encapsulate body))) >> The fact that such a macro call embedded in another form building form >> that processes it properly doesn't mean that it is not bad style: it >> has to do something special to the result of ifdef to make it work. >> If you extract that ifdef call to run it at the repl, it just cannot >> work. > > Yes. -- __Pascal Bourguignon__