<p dir="ltr">Hi Daniel,</p><p dir="ltr">I'm glad to be part of the discussion :)</p>
<div class="gmail_quote">On Aug 28, 2012 8:53 PM, "Daniel Gackle" <<a href="mailto:danielgackle@gmail.com" target="_blank">danielgackle@gmail.com</a>> wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>Hi Red,</div><div><br></div><div>I was hoping you'd chime in. I'll see your scenario 3 and raise you a</div><div>3a and a 3b:</div><div><br></div><div>Scenario 3a: A non-Parenscript function that calls a mv-returning</div>
<div> Parenscript function but only needs its first return value;</div><div><br></div><div>Scenario 3b: A non-Parenscript function that calls a mv-returning</div><div> Parenscript function and needs all its return values.</div>
<div><br></div><div>3a works fine as long as the MV implementation is careful to use a</div><div>normal JS return to pass the first return value back to the caller.</div><div>That's true both of what PS does today and of the global-var proposal.</div>
<div><br></div><div>As for 3b (the scenario, not the hacker!), seems to me this can't work</div><div>at all and there's no need to support it. If you're a non-PS function</div><div>then by definition you can't use PS's MULTIPLE-VALUE-BIND to access</div>
<div>the additional return values because the MV construct only exists in</div><div>PS. I suppose if you really wanted to you could manually write JS to</div><div>do whatever PS does to supply those values to the caller, but then</div>
<div>you're not really a non-PS function anymore, so much as a</div><div>manually-compiled PS function.</div><div><br></div><div>Daniel</div></blockquote><div><br></div><div>I wasn't clear in my original post. I'm not concerned with the non-Parenscript function's ability to receive multiple values. I'm concerned that the non-Parenscript function will interfere with the multiple value return.</div>
<div><br></div><div>If a non-Parenscript function calls a Parenscript function that messes with the global variables, the non-Parenscript function could end up returning stuff unintentionally. This is because the non-Parenscript function will not manipulate the global variables to clean up the unused multiple values that are returned.</div>
<div><br></div><div>Here's some code to illustrait the point:</div><div><br></div><div>(defun ps-foo ()</div><div> (multiple-value-bind (a b) (bar)</div><div> (+ a b)))</div><div><br></div><div>(defun ps-fn-returns-mv ()</div>
<div> (values 1 2))</div><div><div><br class="Apple-interchange-newline">function barWorks() {</div><div> return psFnReturnsMv();</div><div>}</div></div><div><br></div><div><div>function barBreaks() {</div><div> psFnReturnsMv(); // global variables for MV returning get set up and linger</div>
<div> // return a single value: 42</div><div> return 42;</div><div>}</div></div><div><br></div><div>Let's assume the two Parenscript functions translate into something like this:</div><div><br></div><div>var RETURN_VALUES = null;</div>
<div>var MV_CALL = false;</div><div>... other global variables related to multiple values</div><div><br></div><div>function psFoo() {</div><div> // global variable stuff</div><div> MV_CALL = true;</div><div> RETURN_VALUES = null;</div>
<div> </div><div> var a = bar();</div><div> MV_CALL = false;</div><div> var b = RETURN_VALUES ? RETURN_VALUES[0] : undefined;</div><div> return a + b;</div><div>}</div><div><br></div><div>function psFnReturnsMv() {</div>
<div> if (MV_CALL)</div><div> RETURN_VALUES = [ 2 ];</div><div> return 1;</div><div>}</div><div><br></div><div><br class="Apple-interchange-newline">When bar = barWorks, foo will return 1 + 2, as intended. When bar = barBreaks, foo will incorrectly return 42 + 2 because the global variables were not properly cleaned up.</div>
<div><br></div><div>I hope this makes sense.</div><div><br></div><div>- Red</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><br></div><br><div class="gmail_quote">
On Tue, Aug 28, 2012 at 8:46 PM, Red Daly <span dir="ltr"><<a href="mailto:reddaly@gmail.com" target="_blank">reddaly@gmail.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="gmail_quote"><div>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><div>The last discussion: <a href="http://lists.common-lisp.net/pipermail/parenscript-devel/2009-October/000639.html" target="_blank">http://lists.common-lisp.net/pipermail/parenscript-devel/2009-October/000639.html</a></div>
<div><div>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div><br>
(defun blah ()<br>
(values 1 2 3))<br>
<br>
(defun foo ()<br>
(blah)<br>
</div> (some-random-js-function))<br>
<div><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><font color="#888888"><br>
Vladimir<br>
</font></span><div><div><br>
On Tue, Aug 28, 2012 at 10:07 PM, Daniel Gackle <<a href="mailto:danielgackle@gmail.com" target="_blank">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></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><span><font color="#888888"><div><br></div><div>
- Red</div></font></span><div><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><div>
><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" target="_blank">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" target="_blank">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" target="_blank">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" target="_blank">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" target="_blank">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" target="_blank">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></div></div><br>
<br>_______________________________________________<br>
parenscript-devel mailing list<br>
<a href="mailto:parenscript-devel@common-lisp.net" target="_blank">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></blockquote></div><br>
<br>_______________________________________________<br>
parenscript-devel mailing list<br>
<a href="mailto:parenscript-devel@common-lisp.net" target="_blank">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></blockquote></div>