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