[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Multiple-value SETQ/RETURN



Actually, I am not all that thrilled with multiple value returns.
Chuck Linton needed to run some of HIC's lispm code in maclisp,
so instead of changing the multiple value returns into 
"(PROGN (SETQ *RETURN1* <FOO>) (SETQ *RETURN2* <BAR>))" by hand
I made up a little macro to hide the SETQ's.

The reason I am not too thrilled is that multiple value return
complicates the compiler, and cannot be done correctly with a macro,
(remember that I impose a condition, that macros are not allowed
to call macro-expand).

You mention in NIL;NEWFUN > that the following will not
work correctly in NIL:

(MSETQ-CALL (X Y)
	    (PROG1 (FIND-POLAR-POSITION SHIP) (FROB)))

This may make MSETQ-CALL dangerous to use in code which undergoes
macro expansion. The poor luser writes (MSETQ-CALL (X Y) (FOO)) and (FOO)
expands. Resticting what (FOO) can expand into is a gross violation
of the lisp semantic contract. Do you seriously want to introduce
a language construct for which you are unable to generate correct code?

Right now I am thinking about working on a maclisp macro which works
in the above case, (it violates my condition of course), using the
same META EVALUATOR code that I suggested JKF use for lambda-binding
optimization (remember &PROTECT). That suggestion met with such
positive response of course!

The way it works is to generate temporaries for X and Y. GENSYMS.
And then target these to recieve the return values of the PROG1.
The PROG1 the targets these to recieve the return values of its
first argument, and so on. It is incredibly simple to do if
you are not worried about the efficiency of the number of needless
LAMBDA BINDs or SETQ's that you generate. Look what might be
generated:

(MSETQ-CALL (X Y) (SOME-SUBR)) ; SOME-SUBR is not a macro.

(PROGN (SETQ G0001 (SOME-SUBR)  
             G0002 *RETURN-REGISTER-2* 
	     X G0001
             Y G0002)
       G0001)

Of course, the over-caution lets you generate CORRECT code for the PROG1.

(PROGN (SETQ G0001 (FIND-POLAR-POSITION SHIP)
	     G0002 *RETURN-REGISTER-2*)
       ; now we can evaluate the rest of the PROG1 without worry.
       (FROB)
       ; now take care of the MSETQ
       (SETQ X G0001 Y G0002)
	; lastly, the return value of prog1 and the MSETQ
       G0001)

I have left out the details of where the temporaries get allocated.
Wrapping a (LET (G0001 G0002) ...) around things suggests that
they get pushed onto some stack as needed.

So JONL, do you think you can get this to work correctly and efficiently
in NIL?