[comp.lang.lisp.x] Summary & Solution: `Can I do multiple value returns in X-Lisp?'

tony@oha.UUCP (Tony Olekshy) (02/06/91)

On Thu, 31 Jan 1991 18:00:59 MST, in <9101311801.AA20837@oha.uucp>, I wrote:
> 
> I am trying to write a macro that sets the value of each symbol in a list
> of symbols to the corresponding value from a list of values [...]
> 
> 	(defmacro setset (names vals)
> 	    `(mapcar (lambda (n v) (set n v)) ,names ,vals))
> 
> [nope...]  Reading leads me to believe that this a property of set [...]

Hugh Secker-Walker (hugh@ear.mit.edu) & Chris Riesbeck (riesbeck@ils.nwu.edu)
confirmed that set (like eval, Chris says) only works on globals (I eventually
figured that out from Steele).  Hugh said that some trick could be performed
with some old eval function, along the following lines, but I didn't pursue
it...

    (defmacro setset (names values)
	(append '(setq)
	    (apply #'nconc (mapcar #'list (old-eval names) (old-eval values)

Hugh also pointed me towards Cesar Quiroz's multiple-value-returns stuff in
cl.el.  His package consists of two global state variables, five macros, and
two functions (according to Hugh), but I didn't pursue that either.

Chris provided the following code, which does do something like what I want:

    (defun values (&rest args) args)   ;;for clarity

    (defmacro multiple-value-bind (vars exp &rest body)
	`(apply #'(lambda ,vars ,@body) ,exp))

    (defun baz () (values 234 436))

    (multiple-value-bind (foo bar) (baz)
	(print (list foo bar)))

    => (234 436)

As Chris points out, the nice thing about this is that if you move to Common
Lisp, you're code could potentially be more efficient, no longer constructing
and deconstructing lists.  However, the problem with this solution is that
the binding is local to the macro.  I want to be able to set global & instance
variables too.

Chris also hints that there could be non-trivial performance hits with all
this fiddling (instead of just using a temporary variable and taking it apart,
I add).  Hugh also hints that his comments are based on avoiding messing with
the C, and Tom Almy (toma@sail.labs.tek.com) said it couldn't be done in
X-Lisp, by which I presume he meant it would take some C code, because that's
how I solved it.

The C isn't a problem, because I'm using X-Lisp to provide an integration and
extension language to marry a manager of user interface managers, and a
manager of database managers, into a coherent application development
environment (so I've already added lots of C, and support for run-time
additions to the funtab so I can link differing extension libraries with the
same base X-Lisp).

As you can probably tell, the last 12 years of C coding clearly show through
my limited lisp experience, but in this case it helps somewhat.  Here then is
my solution to the problem posted at the beginning of this article.

Sample Invocation...

    (msetq foo bar ... '(123 456 ...))

FSUBR msetq Source Code...

    LVAL msetq()
    {
	LVAL	 vlist;
	LVAL	 vals;
	int	 i;

	/* Get the values argument and evaluate it (we are an FSUBR). */

	if (xlargc < 2) xltoofew();

	xlsave1(vlist); vals = vlist = xleval(xlargv[xlargc-1]);

	/* Now go through the symbols list assigning from the values list. */

	for (i = 0; i <= xlargc; i += 1) {

	    if (is_nil(vals)) xlfail("not enough values");

	    xlsetvalue(xlgasymbol(), car(vals)); vals = cdr(vals);
	    }

	xlpop();

	return (vlist);

	}   /* End of msetq. */

I hereby place this version of msetq under the most liberal copyright allowed
by X-Lisp itself.  If any further commentary results from this posting, I will
update the code and re-post.  Thanks to Hugh, Chris, and Tom.

--
Yours etc., Tony Olekshy.       Internet: tony%oha@CS.UAlberta.CA
				  BITNET: tony%oha.uucp@UALTAMTS.BITNET
				    uucp: alberta!oha!tony
				   Voice: +1 403 425 9657
Where the spirit does not work with the hand there is no art. --Da Vinci