[parenscript-devel] A simpler way to do multiple value return? (Was: PS test failures in 7be9b45)

Daniel Gackle danielgackle at gmail.com
Wed Aug 29 02:41:12 UTC 2012


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 at 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 at 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 at 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 at 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 at common-lisp.net
> >> >
> http://lists.common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
> >> >
> >>
> >> _______________________________________________
> >> parenscript-devel mailing list
> >> parenscript-devel at 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 at common-lisp.net
> > http://lists.common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
> >
>
> _______________________________________________
> parenscript-devel mailing list
> parenscript-devel at common-lisp.net
> http://lists.common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/parenscript-devel/attachments/20120828/32b06530/attachment.html>


More information about the parenscript-devel mailing list