<div>Um, and duh: implicit arg technique fails to do any passthrough at all in</div><div>most cases:</div><div><br></div><div> (defun foo ()</div><div> (multiple-value-bind (a b) (bar) // ignore a</div><div> b))</div>
<div><br></div><div> (defun bar ()</div><div> (baz))</div><div><br></div><div> (defun baz ()</div><div> (values 10 20))</div><div><br></div><div>MV semantics ought to hop along the chain FOO->BAR->BAZ and back, but</div>
<div>here BAR does nothing to forward the arguments list, so BAZ never gets an</div><div>implicit MV array to populate. In other words, implicit arg in general is good </div><div>for one call only, which is not good enough. </div>
<div><br></div><div>I'm surprised I didn't see this before. It only became obvious to me</div><div>after that last point about tail calls.</div><div><br></div><div>Daniel</div><div><br></div><br><div class="gmail_quote">
On Mon, Sep 3, 2012 at 12:58 PM, Daniel Gackle <span dir="ltr"><<a href="mailto:danielgackle@gmail.com" target="_blank">danielgackle@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>You've convinced me about subtle bugs. But I would like to get clear</div><div>about the root difficulty. I don't think this quite captures it:</div><div class="im"><div><br></div><div>< Except as you point out the multiple-values array will now be passed</div>
<div>on to any functions whose value BAR returns ></div><div><br></div></div><div>... because if BAR *returns* that other function's value(s) then we</div><div>actually want whatever it puts in the MV array - yes? That is, in the</div>
<div>following:</div><div><br></div><div> (defun foo ()</div><div> (multiple-value-bind (a b) (bar) // ignore a</div><div> b))</div><div> </div><div> (defun bar ()</div><div> (apply #'baz arguments))</div>
<div> </div><div> (defun baz ()</div><div> (values 10 20))</div><div><br></div><div>... FOO should return 20, so it's good that the MV semantics pass</div><div>through BAR to BAZ. The problem comes when BAR *doesn't* return its</div>
<div>call to BAZ, and BAZ has populated the MV array with bogus values:</div><div><br></div><div> (defun bar ()</div><div> (apply #'baz arguments)</div><div> nil)</div><div><br></div><div>Now FOO should clearly not return 20. Does this illustrate what you</div>
<div>are objecting to?</div><div><br></div><div>What I find interesting is how the different implementations we've been</div><div>discussing all seem to break on the same thing. Correct compilation of</div><div>MVR requires distinguishing between function calls in a tail position</div>
<div>(where MV passthrough is wanted) and those not in a tail position</div><div>(where MV passthrough is a bug). That is, the granularity within which</div><div>MV state should be shared and outside which it must not leak is: a</div>
<div>chain of function calls in the tail position.</div><div><br></div><div>That explains why the proposed implementations so far are incorrect:</div><div>implicit argument as described above, MV_RETURNS (because MV state is</div>
<div>global), and <a href="http://foo.mv" target="_blank">foo.mv</a> (because MV state is per-function [1]). None of</div><div>them works at this granularity.</div><div><br></div><div>So two questions: 1) is this explanation of the difficulty correct?</div>
<div>2) Is there a way for PS to ensure that MV state can't leak outside a</div><div>chain of tail calls? A naive way to do it would be to generate code to </div><div>clear MV state after every non-tail call.</div><div>
<br></div><div>Daniel</div><div><br></div><div>[1] With respect to the <a href="http://foo.mv" target="_blank">foo.mv</a> implementation, we had talked about</div><div>things breaking on recursion. It's worth noting that recursion and MV</div>
<div>work fine together as long as the MV calls are tail calls. e.g. BAR</div><div>returns 6 here:</div><div><br></div><div> (defun foo (list)</div><div> (cond ((null list) (values 1 2 3))</div><div> (t (foo (cdr list)))))</div>
<div> </div><div> (defun bar ()</div><div> (multiple-value-bind (a b c) (foo '(blah blah))</div><div> (+ a b c)))</div><div class="HOEnZb"><div class="h5"><div><br></div><br><div class="gmail_quote">On Mon, Sep 3, 2012 at 8:55 AM, 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"><div>> I'd be interested to see examples that break on the implicit MV arg<br>
> that don't already break on &key. Passing the arguments pseudo-array<br>
> on, for example, shouldn't break. It just throws the responsibility<br>
> for parsing the MV arg on to somebody else, which in non-MV-aware<br>
> cases will typically ignore it and in MV-aware cases will handle it<br>
> according to the protocol.<br>
<br>
</div>If you call a function FOO with &key parameters you're expecting it to<br>
be a PS function, and if function FOO calls other functions they don't<br>
care. You can make the same argument for calling a function BAR<br>
expecting multiple values. Except as you point out the multiple-values<br>
array will now be passed on to any functions whose value BAR returns,<br>
which might or might not lead to subtle bugs. So I am really opposed<br>
to this approach.<br>
<span><font color="#888888"><br>
Vladimir<br>
</font></span><div><div><br>
> It strikes me that the implicit MV arg is a generalization of the &key<br>
> mechanism where the key is not a symbol (string) but a sentinel<br>
> object. The big break with current practice is that it's hidden rather<br>
> than specified by the user at the source level. Makes me wonder if a<br>
> different syntax than MULTIPLE-VALUE-BIND might help - something to<br>
> make the underlying mechanism less unexpected...<br>
><br>
> To be sure, it's a hack and not at all what one would do with proper<br>
> access to the internals. But I wonder if it's as good as we're likely<br>
> to get by way of a correct implementation.<br>
><br>
><br>
> On Sun, Sep 2, 2012 at 6:28 PM, Vladimir Sedach <<a href="mailto:vsedach@gmail.com" target="_blank">vsedach@gmail.com</a>> wrote:<br>
>><br>
>> > We may have crossed a wire here. When you said, "You can do that with<br>
>> > a global table instead of setting a property on the function object,"<br>
>> > I thought you had in mind a global table keyed by function *name*,<br>
>> > which is why I asked about lambdas since they have no names. JS won't<br>
>> > let you use a function object as a key so one would have to concoct<br>
>> > some naming scheme.<br>
>><br>
>> For my first prototype for the new MV mechanism, that's what I thought<br>
>> and used gensyms. But then I tried foo[<function object>] and that<br>
>> works in both FF and CL-JS. But looking at ECMAScript, property<br>
>> identifiers do indeed have to be JavaScript String objects<br>
>> (<a href="http://ecma-international.org/ecma-262/5.1/#sec-8.10" target="_blank">http://ecma-international.org/ecma-262/5.1/#sec-8.10</a>).<br>
>><br>
>> > Moreover, if it worked for MV, the sentinel idea could be used to tag<br>
>> > anything else we wanted into the call. Seems like that could be pretty<br>
>> > powerful.<br>
>> ><br>
>> > Where does this break?<br>
>><br>
>> It wouldn't work for calling JavaScript functions that used the<br>
>> arguments pseudo-array, either for arbitrary arity or for passing<br>
>> arguments on. There's lots of JS functions around that do things like<br>
>> foo.apply(null, slice(arguments, x)) or whatever.<br>
>><br>
>> > p.s. There's also a way to communicate exactly how many return values<br>
>> > are desired, short-circuiting any computation that might be needed to<br>
>> > generate the full VALUES list. (I think this point is independent of<br>
>> > the above idea but I'll adapt the same examples.) Suppose we have:<br>
>><br>
>> In general you have to evaluate all the expressions given to values<br>
>> for their side-effects, so this would only save a few assignments.<br>
>><br>
>> Vladimir<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>
> _______________________________________________<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><br>
</div></div></blockquote></div><br>