Subject: Re: Macros OR, AND From: Erik Naggum <erik@naggum.net> Date: Sun, 18 Nov 2001 03:07:11 GMT Newsgroups: comp.lang.lisp Message-ID: <3215041628177349@naggum.net> * Thomas F. Burdick | But this is exactly the weird case! expensive-general-case can return | multiple values, but cached-result can't! Oh, but I used my own definition of the macro or that solves this problem, and you SHOULD NOT use the braindamaged standard macro. :) But seriously, I recognize your problem. It might actually be a good idea to specify or and cond to be multivalued -- it would not take a huge effort to provide compiler support for this, but there is a little more effort involved when interpreted. However, one of the problems with multivalued functions is that the caller context knows whether it will return single or multiple values, but nobody is listening. That is, if a function may be multivalued, it should be able to skimp on the cost of preparing for returning multiple values if only the primary value is used. This might, understandably, have created a reluctance to use multiple values by default. The "problem" of communicating the expectation of multiple values has some similarities with the annoying tail-call problem, but fortunately, a compiler or interpreter will have to know how to set up its multivalue return mechanism or pass through whatever the value-returning form of the function returned, so the point where this information would both be passed _and_ understood is already known. However, there is no language support for this knowledge, so there is no way to utilize that knowledge. E.g., cond would need to know whether the "calling" form was about to return its value or not to make this painless and transparent insead of costly and cumbersome. The typical implementation of the macro or is to use the feature of the macro cond that it return the value of the test-form if there are no body forms, but it is specified to return only the primary value in that case. To amend this would require some work. If a cond form transform into an if form like this: (cond (test-form) ...) -> (let ((<gensym> test-form)) (if <gensym> <gensym> (cond ...))) It would have to be something like this -> (let ((<gensym> (multiple-value-list test-form))) (if (first <gensym>) <gensym> (cond ...))) except that the internal multivalue return mechanism would probably be used instead of going through the expensive list representation, such that it would not actually need to allocate anything in the caller. (I am concerned with this only because the penalty for using multiple values should be so low that people would not have to think twice about it.) In order for this to _really_ work well, a new language feature would be very welcome. Implementations already have to have _some_ means to return multiple values, so suppose that multiple values were represented by a first-class object instead of the sort of "transient" magic it is today. The function values would create and return such an object. If stored in a variable and later referenced, its value would be the primary value. If referenced by the multivalue special operators, it would work just like it were the original call to values as we are used to it today in the form of storing the value of multiple-value-list and expanding it back to multiple values with (apply #'values <list>). The complicating situation here is that this new kind of first-class object needs to work transparently as if it were its primary value. (Back on the good old PDP-10 this kind of data-driven indirection would not have been a problem, but sadly, modern processors are so deficient. Then again, many things would not have been problems if the PDP-10 had been the model for modern processors. You who knew the PDP-10, know what I mean. The rest should know that this not mere nostalgia.) Note that this would make the original expansion of cond continue to work with multiple values. It would also mean we would have an asymmetry that some might find quite disconcerting: (let* ((foo (values 1 2 3)) (bar foo)) (list (eq foo bar) (multiple-value-list foo) (multiple-value-list bar))) => (t (1 2 3) (1)) | (I can understand not being able to name that macro, though. I started | naming things ...-maybe that would have had super long names, and I | didn't like it at first, but I got used to it. It's probably a bad name, | but it's fine for my personal use :) ) Perhas something along the line of intern? | This is a case where I wonder if the flexibility of macros hasn't maybe | prevented a more powerful notation from having developed, because we can | fake it every specific time we need it. Oh well. Well, we have symbol-macros, which can be really powerful, too, once people figure out how to use them. Making the full use of existing features is quite hard, so it may be that implementing something on top of macros simply does not yield enough of an inconvenience to spawn serious interest in alternatives? That is, not the flexibility of macros, but the lack of inconvenience in doing something with them. /// -- Norway is now run by a priest from the fundamentalist Christian People's Party, the fifth largest party representing one eighth of the electorate. -- Carrying a Swiss Army pocket knife in Oslo, Norway, is a criminal offense.