[parenscript-devel] Patch: added JS label/break to PS
Daniel Gackle
danielgackle at gmail.com
Sat Nov 13 21:48:07 UTC 2010
Sorry for being lazy, but can you post an example or two? This is a feature
I will definitely try out. One of the unwanted weaknesses of my code on the
JS side is the inability to get out of a top level function from inside a
lambda.
On Sat, Nov 13, 2010 at 2:11 PM, Vladimir Sedach <vsedach at gmail.com> wrote:
> I just pushed a patch that tries to do the right thing with both
> lexical and dynamic-extent BLOCK (including implicit BLOCK forms) and
> RETURN-FROM. It's also supposed to provide backwards-compatibility
> with the old-style RETURN behavior (although that does issue a
> warning).
>
> The big thing is that right now in most of the interesting cases it
> does the control jump, but does not return a value. That will be fixed
> in future patches.
>
> I haven't really tested it, so try it out and let me know what breaks.
>
> Vladimir
>
> 2010/8/18 Daniel Gackle <danielgackle at gmail.com>:
> > I like your suggestion of emitting TRY/CATCH only in the cases where
> > it's necessary, i.e. only when trying to escape out of more than one
> > level of function nesting, seems like a good way to go. Then you're
> > only paying for the ugliness when you need it. It's in keeping with
> > PS's philosophy of staying close to what one would write by hand.
> >
> > On Wed, Aug 18, 2010 at 6: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
> >
> >
> > _______________________________________________
> > 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/20101113/2342ecf7/attachment.html>
More information about the parenscript-devel
mailing list