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