Awesome!<br clear="all"><br>_Nick_<br><br>
<br><br><div class="gmail_quote">On Wed, Aug 18, 2010 at 5:14 AM, Red Daly <span dir="ltr"><<a href="mailto:reddaly@gmail.com">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;">
Sorry, I forgot the link.  See<br>
<a href="http://github.com/gonzojive/parenscript/commit/d8ebace1bcd60a57470d7a8cf0d4e351b7645e8e" target="_blank">http://github.com/gonzojive/parenscript/commit/d8ebace1bcd60a57470d7a8cf0d4e351b7645e8e</a><br>
for the commit that adds this.<br>
<br>
My Parenscript branch is now pretty much in sync with the main branch,<br>
with only 2 mostly cosmetic test failures<br>
<font color="#888888"><br>
Red<br>
</font><div><div></div><div class="h5"><br>
On Wed, Aug 18, 2010 at 5:12 AM, Red Daly <<a href="mailto:reddaly@gmail.com">reddaly@gmail.com</a>> wrote:<br>
> I added RETURN-FROM and BLOCK without too much effort using the<br>
> implicit return functionality and try/catch. In my view this is the<br>
> most reasonable way to implement this in the general case, since<br>
> BLOCK/RETURN-FROM require non-local exit much in the same way that<br>
> lisp's TRY/CATCH do.<br>
><br>
> The alternative to this approach is to exit from each function in the<br>
> call stack via a Javascript `return' statement.  Unfortunately, the<br>
> call stack can contain many functions code over which the Parenscript<br>
> compiler exerts little control, requiring throw as the control<br>
> transfer mechanism.  Thus, in the general case of unknown code on the<br>
> call stack, there is no means to exit without a throw.  I do not view<br>
> throwing as an ugly solution at all, since try/catch was designed for<br>
> non-local exits of all sorts.<br>
><br>
> Nonetheless, using try/catch to implement Parenscript features<br>
> deserves some attention.  Programs will need to ensure that they do<br>
> not use try/catch in a way that interferes with the Parenscript<br>
> convention.  Generally, try/catch blocks should only catch specific<br>
> exceptions and re-throw PS's exceptions.   I'm happy to also implement<br>
> a safe TRY/CATCH wrapper that re-throws Parenscript errors and catches<br>
> everything else, too.  However, we may want to make an official<br>
> interface change to try/catch if any lisp-style non-local exit code<br>
> becomes part of the language.<br>
><br>
> I present an example of why try/catch is unavoidable inline below:<br>
><br>
> On Fri, Apr 9, 2010 at 3:42 PM, Vladimir Sedach <<a href="mailto:vsedach@gmail.com">vsedach@gmail.com</a>> wrote:<br>
>> Makes sense to me. I'll add this to my todo list (which I'll publish<br>
>> in an email as soon as I'm done my current work on the PS compiler).<br>
>><br>
>> Vladimir<br>
>><br>
>> 2010/4/9 Daniel Gackle <<a href="mailto:danielgackle@gmail.com">danielgackle@gmail.com</a>>:<br>
>>> I just pushed a patch (authored by Scott) to implement JS's LABEL and BREAK<br>
>>> in PS. (Note that this patch deprecates LABELED-FOR since you can get the<br>
>>> same effect by combining LABEL and FOR. Was anybody using LABELED-FOR?)<br>
>>> Here's an example:<br>
>>> (label scope<br>
>>>     (foo)<br>
>>>     (when (bar)<br>
>>>       (break scope))<br>
>>>     (blee))<br>
>>> =><br>
>>> scope: {<br>
>>>     foo();<br>
>>>     if (bar()) {<br>
>>>         break scope;<br>
>>>     };<br>
>>>     blee();<br>
>>> };<br>
>>> I was astonished to discover recently that JS has supported this ability all<br>
>>> along in the form of labeled statements and labeled breaks. I'd always<br>
>>> assumed that to get explicit returns from an arbitrary scope, you'd have to<br>
>>> resort to the ugly hack of muscling TRY/CATCH to do it, thinking that this<br>
>>> was the closest JS counterpart.<br>
>>> (See <a href="http://news.ycombinator.com/item?id=793092" target="_blank">http://news.ycombinator.com/item?id=793092</a> for a thread in which<br>
>>> several people believe this.) But it appears we were all wrong.<br>
>>> What's not clear yet is how far this can be taken. Can you use it inside a<br>
>>> nested local function to return immediately from the top-level function?<br>
>>> That is one thing I've wanted for a long time.<br>
>>> In the ideal case, LABEL/BREAK could be used as a base for implementing a<br>
>>> proper BLOCK and RETURN-FROM in PS, something which we'd long believed to be<br>
>>> impossible. One challenge is that in CL, RETURN-FROM can take a value, which<br>
>>> becomes the value of BLOCK. In other words, BLOCK in CL is an expression<br>
>>> while LABEL in JS is not. It seems, though, that most of this challenge has<br>
>>> already been conquered with the development of implicit return in PS. The<br>
>>> only thing you'd need to add is detecting when BLOCK is being used as an<br>
>>> expression, declaring a gensymed variable and assigning whatever is<br>
>>> happening inside BLOCK to that variable (much like implicit return already<br>
>>> does with e.g. CASE), then put the variable in the expression position that<br>
>>> BLOCK was in. It seems like this ought to work. It would also make things<br>
>>> like this possible in PS:<br>
>>> (1+ (case foo<br>
>>>         (:eleven 11)<br>
>>>         (:twelve 12)))<br>
>>> Vladimir (and everybody), is the above clear? What do you think of it?<br>
><br>
> As stated above, I think try/catch is the way to go.  There is no<br>
> other way to exit a stack of functions in the general case otherwise.<br>
><br>
> For example, I can write a Javascript function that calls its argument<br>
> infinity times and never returns.<br>
><br>
> function mapForever(fn) {<br>
> while(true) fn();<br>
> }<br>
><br>
> Now consider some parenscript:<br>
><br>
> (block non-local<br>
>  (map-forever<br>
>    (lambda ()<br>
>      (return-from non-local "we got out!"))))<br>
><br>
> To extricate itself from map-forever, there is no alternative but JS's<br>
> throw statement.<br>
><br>
> Even if we had the ability to alter every function in the system, it<br>
> would be necessary to inspect nearly every function call's return<br>
> values to properly unwind the stack to the appropriate BLOCK.<br>
><br>
> Having said all that, there are cases when try/catch is not necessary<br>
> for BLOCK/RETURN-FROM, as you have described.  BLOCK should emit code<br>
> according to the contexts in which RETURN-FROM appears.  If there is a<br>
> RETURN-FROM inside the same function, BLOCK can use a label for a<br>
> local exit.  If RETURN-FROM appears inside a lambda, try/catch is<br>
> necessary (except in cases where you want to optimize this away by<br>
> inspecting how that lambda gets passed around).  If there are no<br>
> return-froms, just emit a PROGN.<br>
><br>
> My solution does not do the local optimization, but it does refrain<br>
> from putting try/catches around code with no return-froms.<br>
><br>
><br>
><br>
> Red<br>
><br>
>>> Daniel<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://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel" target="_blank">http://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">parenscript-devel@common-lisp.net</a><br>
>> <a href="http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel" target="_blank">http://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">parenscript-devel@common-lisp.net</a><br>
<a href="http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel" target="_blank">http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel</a><br>
</div></div></blockquote></div><br>