Good memory!
This arguably moves the balance a bit in *favor* of the simpler implementation, because this bug is a little less likely to come up in practice than the existing bug PS. (Obviously it would be better to eliminate both bugs.)
Is the compiler allowed to keep track of which functions return multiple values? If so, it could recognize that the call to BLAH is not a return value of FOO and compile FOO like this:
function foo() { blah(); SPILLOVER = null; return someRandomJsFunction(); };
In other words, use it (where returning counts as a use) or lose it.
Daniel
On Tue, Aug 28, 2012 at 8:20 PM, Vladimir Sedach vsedach@gmail.com wrote:
The counter-example to using a global variable as I remember it from the last discussion was this case:
(defun blah () (values 1 2 3))
(defun foo () (blah) (some-random-js-function))
(defun bar () (multiple-value-bind (a b c) (foo) (+ a b c)))
Now a call to bar returns 6, when it shouldn't. I think it might be possible to use another global variable as a flag that's set and checked by multiple-value aware PS functions, but I need to think about how to make it work.
Vladimir
On Tue, Aug 28, 2012 at 10:07 PM, Daniel Gackle danielgackle@gmail.com wrote:
Those test failures make sense now - thanks. Also, this comment reminded me of something:
< the callee.caller property for functions, which multiple value return depends on >
I dislike our implementation for multiple value return. Stuffing the values in callee.caller is complicated and doesn't feel right (I think I may have been the one who came up with it; it was a bad idea), plus it relies on one of the shakiest aspects if not of JS itself than certainly of the JS implementations.
A simpler way occurred to me the other day and I'd like to know where it breaks. The argument goes like this: since JS is single-threaded and functions have to return synchronously, there can be only one function return in play at any given time, therefore there can be only one multiple-return-value list at any time, therefore why not just store it in a global variable?
Say this variable is called *spillover*. Then this:
(defun blah () (values 1 2 3))
(defun callblah () (multiple-value-bind (a b c) (blah) (+ a b c)))
...might compile to:
function blah() { SPILLOVER = [2, 3]; return 1; }; function callblah() { var a = blah(); var b = SPILLOVER[1]; var c = SPILLOVER[2]; return a + b + c; };
There might be complicating factors that would make the JS more involved in practice, but I don't remember what they are.
Apart from being so much simpler, this implementation has two advantages. First, it's "morally" better in Eugenia Cheng's sense (http://cheng.staff.shef.ac.uk/morality/morality.pdf). The multiple return values don't belong to caller or callee, but to the call itself. Caller and callee are functions that persist across many calls and ought not to have information about a specific call attached to them. That's why PS is forced to add ugly code to save the previous value attached to callee and restore it using a try/finally at the end.
Second, it would fix a known problem. PS breaks when you have an interloper like FOO here:
(defun blah () (values 1 2 3))
(defun foo () (blah))
(defun bar () (multiple-value-bind (a b c) (foo) (+ a b c)))
BAR should return 6, and does in CL, but in PS it returns 1, because FOO doesn't return multiple values, so B and C are null and "1 + null + null" is 1 in JS. But the *spillover* hack would make BAR return 6.
Could we get away with this, or what am I missing?
Daniel
On Tue, Aug 28, 2012 at 6:00 PM, Vladimir Sedach vsedach@gmail.com
wrote:
Hi Daniel,
Yes, those two failures in the eval test suite are expected. CL-JavaScript doesn't have the callee.caller property for functions, which multiple value return depends on. I wasn't sure where to comment those tests out, so I left them in to remind myself to add callee.caller to CL-JavaScript (I've already talked to Marijn Haverbeke about that).
Thank you, Vladimir
On Mon, Aug 27, 2012 at 11:58 PM, Daniel Gackle <danielgackle@gmail.com
wrote:
I've rebased my PS LOOP extensions [1] onto the latest commit (7be9b45) and recompiled Skysheet. The generated JS looks fine. There was one glitch that I'll report separately along with a workaround. Before pushing the LOOP extensions onto master, though, I want to update any relevant PS tests. Some will fail because the LOOP output has changed quite a bit. Unfortunately I'm also seeing failures when I run the tests in 7be9b45, which is prior to any of these LOOP changes. I've pasted the output below [2]. It doesn't look like these failures are related to work in ps-loop.lisp, so I'll just ignore them for the time being, but Vladimir can you please comment on whether you know about them or whether there's something unexpected going on?
Daniel
[1] These are the constructs FOR..OF and MAP..TO, plus a change to FOR..ON, that I described in my email to this list on April 11. They are currently sitting in the "loop" branch. Rebasing them was nontrivial because of Boris' additions to ps-loop.lisp, but it seems to have all gone ok. Boris, if you're reading this, please look out
for
any regressions once I push these changes and let us know if you notice anything.
[2] Running output tests:
........................................................................................................................................................................................................................................................................................................................................................................................................................................
Did 424 checks. Pass: 424 (100%) Skip: 0 ( 0%) Fail: 0 ( 0%) Running package system tests: ......... Did 9 checks. Pass: 9 (100%) Skip: 0 ( 0%) Fail: 0 ( 0%) Running CL-JavaScript eval tests: ...........................f...............X...................... Did 66 checks. Pass: 64 (96%) Skip: 0 ( 0%) Fail: 2 ( 3%) Failure Details:
mv-return1 []: Unexpected Error: #<cl-js:js-condition #x30200155257D> [js] TypeError: undefined has no properties...
dynamic-extent-function-return-values []: (funcall (if (typep #:g36204 'structure-object) #'equalp
#'equal)
#:g36204 (jsarray '(1 2 3))) was NIL..
parenscript-devel mailing list parenscript-devel@common-lisp.net
http://lists.common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://lists.common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
Those test failures make sense now - thanks. Also, this comment reminded me of something:
< the callee.caller property for functions, which multiple value return depends on >
I dislike our implementation for multiple value return. Stuffing the values in callee.caller is complicated and doesn't feel right (I think I may have been the one who came up with it; it was a bad idea), plus it relies on one of the shakiest aspects if not of JS itself than certainly of the JS implementations.
A simpler way occurred to me the other day and I'd like to know where it breaks. The argument goes like this: since JS is single-threaded and functions have to return synchronously, there can be only one function return in play at any given time, therefore there can be only one multiple-return-value list at any time, therefore why not just store it in a global variable?
Say this variable is called *spillover*. Then this:
(defun blah () (values 1 2 3))
(defun callblah () (multiple-value-bind (a b c) (blah) (+ a b c)))
...might compile to:
function blah() { SPILLOVER = [2, 3]; return 1; }; function callblah() { var a = blah(); var b = SPILLOVER[1]; var c = SPILLOVER[2]; return a + b + c; };
There might be complicating factors that would make the JS more involved in practice, but I don't remember what they are.
Apart from being so much simpler, this implementation has two advantages. First, it's "morally" better in Eugenia Cheng's sense (http://cheng.staff.shef.ac.uk/morality/morality.pdf). The multiple return values don't belong to caller or callee, but to the call itself. Caller and callee are functions that persist across many calls and ought not to have information about a specific call attached to them. That's why PS is forced to add ugly code to save the previous value and restore it using a try/finally at the end.
Second, it would fix a known problem. PS breaks when you introduce an interloper like FOO here:
(defun blah () (values 1 2 3))
(defun foo () (blah))
(defun bar () (multiple-value-bind (a b c) (foo) (+ a b c)))
BAR should return 6, and does in CL, but in PS it returns 1, because FOO doesn't return multiple values, so B and C are null and "1 + null + null" is 1 in JS. But the *spillover* hack would make BAR return 6.
Could we get away with this, or what am I missing?
Daniel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://lists.common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://lists.common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel