[parenscript-devel] Multiple value calls
Vladimir Sedach
vsedach at gmail.com
Thu Nov 5 05:16:52 UTC 2009
> Ok, here's a variation that abandons global MV altogether and stores it
> instead as a property on the caller.
Oh, wow. The ability to attach arbitrary properties to function
objects finally comes in useful. Very clever!
> It passes all the previously mentioned
> cases and works at least some of the time with anonymous functions.
Why do you say some of the time? Under what cases would it break?
> (defpsmacro values (main &rest additional)
> (with-ps-gensyms (mv)
> `(let ((,mv (list , at additional)))
> (when (defined (@ (@ (@ arguments :callee) :caller) :mv))
> (setf (@ (@ (@ arguments :callee) :caller) :mv) ,mv))
> (return ,main))))
>
> (defpsmacro multiple-value-bind (vars expr &body body)
> (with-ps-gensyms (mv prev)
> `(let ((,prev (@ (@ arguments :callee) :mv)))
> (try
> (progn
> (setf (@ (@ arguments :callee) :mv) t)
> (let ((,(car vars) ,expr)
> (,mv (if (objectp (@ (@ arguments :callee) :mv))
> (@ (@ arguments :callee) :mv)
> (make-array ,(1- (length vars))))))
> (destructuring-bind ,(cdr vars) ,mv
> , at body)))
> (:finally (if (undefined ,prev)
> (delete (@ (@ arguments :callee) :mv))
> (setf (@ (@ arguments :callee) :mv) ,prev)))))))
I think you should push this code as a patch; let's see what happens.
Vladimir
> Specifically, it passes the case in Red's email that broke my previous
> attempt. That is, given ADD-TO-RESULT as defined in that earlier email,
>
> (defun foo ()
> (multiple-value-bind (a b) (add-to-result (lambda (x) (values 1 10)) 2)
> (return (list a b))))
>
> foo() now correctly evaluates to [3,undefined] instead of [3,10].
>
> Can you guys come up with a new case to break it?
>
> Daniel
>
>
>
> On Sun, Nov 1, 2009 at 1:41 PM, Red Daly <reddaly at gmail.com> wrote:
>>
>>
>> On Sun, Nov 1, 2009 at 9:50 AM, Daniel Gackle <danielgackle at gmail.com>
>> wrote:
>>>
>>> It might help to use a PS special variable and make MULTIPLE-VALUE-BIND
>>> responsible for cleanup.
>>>
>>> (ps (defvar *mv* undefined))
>>>
>>> (defpsmacro values (main &rest additional)
>>> (with-ps-gensyms (mv)
>>> `(let ((,mv (list , at additional)))
>>> (when (defined *mv*)
>>> (setf *mv* ,mv))
>>> (return ,main))))
>>>
>>> (defpsmacro multiple-value-bind (vars expr &body body)
>>> `(let ((*mv* '()))
>>> (let ((,(car vars) ,expr))
>>> (destructuring-bind ,(cdr vars) *mv*
>>> , at body))))
>>>
>>> This works in the obvious cases. I'm not sure it handles Red's scenarios.
>>> Red, can you supply an example where this breaks?
>>
>>
>> The main case I am concerned about is dealing with non-parenscript
>> functions that will not manipulate the mv state. Something like the
>> following would break the above code:
>>
>> (defun foo ()
>> (let ((my-callback (lambda (x) (values 1 10)))
>> (multiple-value-bind (a b)
>> (add-to-result my-callback 2)))
>>
>> =>
>>
>> // imagine this is a non-Parenscript function that we cannot manipulate
>> with the
>> // Parenscript compiler
>> function addToResult(callback, x) {
>> // returns the result of adding x to the result of calling the callback
>> return callback() + x;
>> }
>>
>> function foo () {
>> var myCallback = function (x) {
>> if (MV !== undefined)
>> MV = [10];
>> return 1;
>> };
>>
>> var old_MV = MV; // begin let
>> MV = null;
>> var a = addToResult(myCallback, 2);
>> var b = MV ? MV[0] : null;
>>
>> // now b === 10 but it should be nil
>> // this is because addToResult did not reset MV
>>
>> MV = old_MV; // end let
>>
>> }
>>
>> This is why I think you might need to identify the callee in another
>> special variable, and for emitted functions reset the MV_CALLEE variable
>> before returning (and maybe in other places?).
>>
>>
>> Red
>>
>>
>>
>>>
>>> Daniel
>>>
>>> p.s. I took the easy way out of making VALUES always prepend RETURN, but
>>> once Vladimir bestows implicit RETURN upon us we can take that out ;)
>>>
>>>
>>> On Sat, Oct 31, 2009 at 9:53 PM, Red Daly <reddaly at gmail.com> wrote:
>>>>
>>>> I apologize for sending the first half of this email in error earlier:
>>>>
>>>> On Sat, Oct 31, 2009 at 8:35 PM, Red Daly <reddaly at gmail.com> wrote:
>>>>>
>>>>> Hi Parenscripters,
>>>>>
>>>>> As far as I can tell, multiple-value function calls are a unique
>>>>> feature of lisp. I would like the ability to perform multiple-value calls
>>>>> in Parenscript but I don't know if a sane solution exists or not.
>>>>>
>>>>> Can anyone come up with a scheme for returning multiple values that
>>>>> translates well to Javascript? Ideally such a scheme would not introduce
>>>>> much overhead for usual functions that do not use or return multiple values
>>>>> (though perhaps setting some sort of global MV flag might be inexpensive
>>>>> enough). Functions that return multiple values should also only appear to
>>>>> return a single value when called by a function that expects only one return
>>>>> value (including native javascript functions).
>>>>>
>>>>> (defun paren-mv-returner ()
>>>>> (return (values 1 2 3)))
>>>>>
>>>>> =>
>>>>>
>>>>>
>>>>> function parenMvReturner() {
>>>>> /* do some magic with the values 2 and 3 */
>>>>> return 1;
>>>>> }
>>>>>
>>>>> // one implementation might be
>>>>> var mv = undefined;
>>>>>
>>>>> function parenMvReturner() {
>>>>> mv = [2, 3];
>>>>> return 1;
>>>>> }
>>>>>
>>>>> // this scheme needs to adjust the return statement of every function
>>>>> so it might not be sufficient
>>>>> // consider this other function
>>>>>
>>>>> function parenMySingleReturner () {
>>>>> var x = parenMvReturner();
>>>>
>>>> return x;
>>>> }
>>>>
>>>> // parenMySingleReturner() will appear to return multiple values unless
>>>> it modifies the mv value itself
>>>>
>>>> // correction:
>>>> function parenMySingleReturner () {
>>>> var x = parenMvReturner();
>>>> mv = null;
>>>> return x;
>>>> }
>>>>
>>>> But it seems like this solution will fall apart for calls to native
>>>> Javascript functions over which we have no control. If we pass a
>>>> multiple-value returning function as an argument to a native function, the
>>>> native function will not perform the necessary mv-nulling when it returns.
>>>>
>>>> someForeignJavascriptFunction( someMVReturningFunction)
>>>>
>>>> will return whatever the someForeignJavascriptFunction should return,
>>>> but it will also appear to return the other values that
>>>> someMVReturningFunction set in the mv variable, since
>>>> someForeignJavascriptFunction performs no cleanup.
>>>>
>>>> Maybe this limitation can be avoided by having an mv-returning function
>>>> A set a global variable "mvFunctionReturner" equal to the function A and a
>>>> mv-receiver can check that mvFunctionReturner is set according to the
>>>> function it called expecting multiple values. Does this scheme miss any
>>>> cases?
>>>>
>>>> Anyway I have thought a little bit about this and I thought I would pass
>>>> it off to the rest of the Parenscripters as a thought experiment. Assume
>>>> you can do a lot more semantic analysis than Parenscript currently does and
>>>> transform the compiled source however you want. But any compiled functions
>>>> must still be able to be treated as normal Javascript functions and all and
>>>> only functions that should return multiple values appear to return them.
>>>>
>>>> Cheers,
>>>> Red
>>>>
>>>> _______________________________________________
>>>> parenscript-devel mailing list
>>>> parenscript-devel at common-lisp.net
>>>> http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
>>>>
>>>
>>>
>>> _______________________________________________
>>> parenscript-devel mailing list
>>> parenscript-devel at common-lisp.net
>>> http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
>>>
>>
>>
>> _______________________________________________
>> parenscript-devel mailing list
>> parenscript-devel at common-lisp.net
>> http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
>>
>
>
> _______________________________________________
> parenscript-devel mailing list
> parenscript-devel at common-lisp.net
> http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
>
>
More information about the parenscript-devel
mailing list