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();
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@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
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?
What about anonymous functions?
I like this idea, and I think it can be made to work. Have you looked at whether Linj tries to do multiple return values? I suspect someone somewhere has thought about and possibly solved this problem before.
Vladimir
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@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
On Sun, Nov 1, 2009 at 9:34 AM, Vladimir Sedach vsedach@gmail.com wrote:
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?
What about anonymous functions?
It would require that an anonymous function being called in Parenscript source be stored in a variable in the caller. for example, take the (implicitly returning) functions below:
(defun foo () (multiple-value-bind (x y) (funcall (lambda (z) (values z (+ z 17))) 4)))
=> function foo () {
var gensymed_lambda = function(z) { mvFunctionReturner = arguments.callee; mv = [ z+ 17]; return z; } // bind the results of calling the lambda var x = gensymed_lambda(4);
var y = null; if (gensymed_lambda === mvFunctionReturner) y = mv[0];
// now implicitly return the same values mvFunctionReturner = arguments.callee; // arguments.callee === foo unless foo is renamed return x; }
You can deal with anonymous functions basically by naming them, at least in this scheme.
I like this idea, and I think it can be made to work. Have you looked at whether Linj tries to do multiple return values?
Good idea. Linj seems to be defunct and inaccessible, unfortunately.
I suspect someone somewhere has thought about and possibly solved this problem before.
Vladimir
Thanks, Red
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@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
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 ,@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* ,@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?
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@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@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@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
On Sun, Nov 1, 2009 at 9:50 AM, Daniel Gackle danielgackle@gmail.comwrote:
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 ,@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* ,@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@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@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@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
Ok, here's a variation that abandons global MV altogether and stores it instead as a property on the caller. It passes all the previously mentioned cases and works at least some of the time with anonymous functions.
(defpsmacro values (main &rest additional) (with-ps-gensyms (mv) `(let ((,mv (list ,@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 ,@body))) (:finally (if (undefined ,prev) (delete (@ (@ arguments :callee) :mv)) (setf (@ (@ arguments :callee) :mv) ,prev)))))))
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@gmail.com wrote:
On Sun, Nov 1, 2009 at 9:50 AM, Daniel Gackle danielgackle@gmail.comwrote:
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 ,@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* ,@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@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@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@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
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 ,@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 ,@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@gmail.com wrote:
On Sun, Nov 1, 2009 at 9:50 AM, Daniel Gackle danielgackle@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 ,@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* ,@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@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@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@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
< Why do you say some of the time? Under what cases would it break? >
Red will think of something :)
< I think you should push this code as a patch; let's see what happens. >
I'll do that, perhaps once Scott has our code working with the implicit return stuff, to minimize upgrade inconvenience.
< The ability to attach arbitrary properties to function objects finally comes in useful. >
This is actually the one feature of JS that I miss in CL: the ability to attach arbitrary properties to pretty much anything. It is a godsend for exploratory programming since it eliminates the gruntwork of packing things into defined structures (objects, arrays, whatever) which you then have to destructure to get at them. It's an extreme of loosey-gooseyness that must give the static bondage people nightmares (a feature, not a bug). I wish someone would figure out a way to hack the same ability into CL (we've already done so in a limited, good-enough-for-our-app way). It's interesting that symbol-plists just aren't that useful in this regard.
Daniel
On Wed, Nov 4, 2009 at 10:16 PM, Vladimir Sedach vsedach@gmail.com wrote:
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 ,@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 ,@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))
(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@gmail.com wrote:
On Sun, Nov 1, 2009 at 9:50 AM, Daniel Gackle danielgackle@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 ,@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* ,@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@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@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@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
On Thu, Nov 5, 2009 at 10:43 AM, Daniel Gackle danielgackle@gmail.com wrote:
< Why do you say some of the time? Under what cases would it break? >
Red will think of something :)
Well, I think this implementation is quite close and would work with beefier semantic analysis.
< I think you should push this code as a patch; let's see what happens. >
I'll do that, perhaps once Scott has our code working with the implicit return stuff, to minimize upgrade inconvenience.
< The ability to attach arbitrary properties to function objects finally comes in useful. >
This is actually the one feature of JS that I miss in CL: the ability to attach arbitrary properties to pretty much anything. It is a godsend for exploratory programming since it eliminates the gruntwork of packing things into defined structures (objects, arrays, whatever) which you then have to destructure to get at them. It's an extreme of loosey-gooseyness that must give the static bondage people nightmares (a feature, not a bug). I wish someone would figure out a way to hack the same ability into CL (we've already done so in a limited, good-enough-for-our-app way). It's interesting that symbol-plists just aren't that useful in this regard.
Daniel
On Wed, Nov 4, 2009 at 10:16 PM, Vladimir Sedach vsedach@gmail.com wrote:
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 ,@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 ,@body))) (:finally (if (undefined ,prev) (delete (@ (@ arguments :callee) :mv)) (setf (@ (@ arguments :callee) :mv) ,prev)))))))
I think this breaks in the case where EXPR in the above macro has more than one form:
(multiple-value-bind (a b) (progn (returns-mv) (doesnt)) (alert a) (alert b))
Where (defun returns-mv() (values 1 2)) and (defun doesnt () (return 3)).
(As an aside, the evaluation order of the MV arguments is not serial: (values (foo) (bar)) evaluates (bar) first. This is a simple bug that the ONCE-ONLY macro should solve)
This is so close, and I think attaching MV information to the caller is a viable solution, since (1) MV returns only make sense for parenscript functions, not functions written by others, and (2) with just a little bit more semantic analysis we should be able to derive the form that will be responsible for returning the values bound by multiple-value-bind. So good work! This solution will stand for now.
Note, however, that this solution requires every implicit return (e.g. a tail call) to execute the multiple-value machinery. It's probably not a big deal except for certain sections of code, and hey, it's Javascript anyway.
Red
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@gmail.com wrote:
On Sun, Nov 1, 2009 at 9:50 AM, Daniel Gackle danielgackle@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 ,@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* ,@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@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@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@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
Just pushed a version of Daniel's code that avoids the problems you brought up Red.
I have to say again how awesome it is that something like multiple values can be implemented so easily in JavaScript. Extreme late binding really is better than any kind of bolted-on metaprogramming facilities.
Now what remains to be done is VALUES as a setf place.
Thanks, Vladimir
2009/11/25 Red Daly reddaly@gmail.com:
On Thu, Nov 5, 2009 at 10:43 AM, Daniel Gackle danielgackle@gmail.com wrote:
< Why do you say some of the time? Under what cases would it break? >
Red will think of something :)
Well, I think this implementation is quite close and would work with beefier semantic analysis.
< I think you should push this code as a patch; let's see what happens. >
I'll do that, perhaps once Scott has our code working with the implicit return stuff, to minimize upgrade inconvenience.
< The ability to attach arbitrary properties to function objects finally comes in useful. >
This is actually the one feature of JS that I miss in CL: the ability to attach arbitrary properties to pretty much anything. It is a godsend for exploratory programming since it eliminates the gruntwork of packing things into defined structures (objects, arrays, whatever) which you then have to destructure to get at them. It's an extreme of loosey-gooseyness that must give the static bondage people nightmares (a feature, not a bug). I wish someone would figure out a way to hack the same ability into CL (we've already done so in a limited, good-enough-for-our-app way). It's interesting that symbol-plists just aren't that useful in this regard.
Daniel
On Wed, Nov 4, 2009 at 10:16 PM, Vladimir Sedach vsedach@gmail.com wrote:
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 ,@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 ,@body))) (:finally (if (undefined ,prev) (delete (@ (@ arguments :callee) :mv)) (setf (@ (@ arguments :callee) :mv) ,prev)))))))
I think this breaks in the case where EXPR in the above macro has more than one form:
(multiple-value-bind (a b) (progn (returns-mv) (doesnt)) (alert a) (alert b))
Where (defun returns-mv() (values 1 2)) and (defun doesnt () (return 3)).
(As an aside, the evaluation order of the MV arguments is not serial: (values (foo) (bar)) evaluates (bar) first. This is a simple bug that the ONCE-ONLY macro should solve)
This is so close, and I think attaching MV information to the caller is a viable solution, since (1) MV returns only make sense for parenscript functions, not functions written by others, and (2) with just a little bit more semantic analysis we should be able to derive the form that will be responsible for returning the values bound by multiple-value-bind. So good work! This solution will stand for now.
Note, however, that this solution requires every implicit return (e.g. a tail call) to execute the multiple-value machinery. It's probably not a big deal except for certain sections of code, and hey, it's Javascript anyway.
Red
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@gmail.com wrote:
On Sun, Nov 1, 2009 at 9:50 AM, Daniel Gackle danielgackle@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 ,@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* ,@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@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@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@common-lisp.net > http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel >
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel@common-lisp.net