Path: utzoo!news-server.csri.toronto.edu!cs.utexas.edu!swrinde!elroy.jpl.nasa.gov!usc!snorkelwacker.mit.edu!ai-lab!zurich.ai.mit.edu!markf From: markf@zurich.ai.mit.edu (Mark Friedman) Newsgroups: comp.lang.scheme Subject: Re: Why macros impair readability Message-ID: Date: 8 Mar 91 18:48:00 GMT References: <9103071300.aa28959@mc.lcs.mit.edu> Sender: news@ai.mit.edu Reply-To: markf@zurich.ai.mit.edu Organization: M.I.T. Artificial Intelligence Lab. Lines: 94 In-reply-to: markf@zurich.ai.mit.edu's message of 7 Mar 91 19:32:46 GMT You know that something's wierd when you reply to your own response. I realize that I have boxed myself into a corner with my "macros DON'T impair readablity" statements. I will now try to wrestle myself out of the corner with a new statement: Macros themselves are unreadable. I think that this is more the crux of the matter than Jaffer's complaints about not knowing when something is a macro or Turbak's complaints about the dangers of using macros. Consider a procedure like: (define (foo bar) (let ((baz (grumble bar))) (mumble (stumble baz) (fumble baz)))) We like to say something like: First set baz to grumble of bar then compute stumble of baz and fumble of baz and then apply mumble to those. Now consider: (define-macro (foo bar) (let ((baz (grumble bar))) (mumble (stumble baz) (fumble baz)))) Now the the same description applies, but it is not a semantically meaningful description of what foo does. It is a description of the construction of something which does foo. It is the wrong (for us) level of description. What's more, the more we modularly decompose or macro definitions the harder things get. The program fragments get less meaningful and the combining process gets more complex. This, of course, is not susprising. After all macros don't specify (run time) processes, they specify program constructions which specify processes. Procedures, however, do describe processes - or do they? Well at one level, yes they do. You plug the definition of the procedure into the Scheme evaluation rules and a process ensues. But an interesting question - and the one that is relevant to the readability issue - is: Does a Scheme procedure definition describe a process that we can understand. That is, does our idea of a process match Scheme's idea of a process. I think that for many of us the answer is no, and the reason is similar to the reason why macros are hard to understand. Consider the following program snippet: (define (tough foo) (((((foo 10) 'bar) 12.2) 'wow) 0)) (define (foo bar) (foo2 (whoknows bar))) (define (foo2 bar) (lambda (x) (foo3 (mumble x) (rumble bar)))) (define (foo3 bar baz) (lambda (x) (lambda (y) (stumble x y (lambda (foo (zaz bar))) (baz))))) ... Many people find programs like these hard to understand. A large part of the reason is that they construct and combine procedure fragments (i.e. lambda expressions). These procedure fragments are similar to the program fragments created and combined by macros. Perhaps most importantly, the order of execution of these fragments is not immediately apparent. They may get stored for awhile or passed around for awhile before they are applied. This again is similar to the situation with macro definitions where the program fragments may be arbitrarily combined. The question still remains however of why these things are hard to understand. After all the Scheme evaluation rules are fairly simple. I haven't even used side effects or call-with-current-continuation or even an IF in the above examples. I don't really have an answer for this but I suspect that many of us have an essentially serial, imperative, limited stack (and heap) mind set that doesn't match very well with the evaluation of procedures like the ones given and complex macro constructions. -Mark -- Mark Friedman MIT Artificial Intelligence Lab 545 Technology Sq. Cambridge, Ma. 02139 markf@zurich.ai.mit.edu