[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