Thank you for these examples, and sorry for the delay in replying. They are invaluable in figuring out what you've done with BLOCK and RETURN-FROM.
In example #5, the following line: err['ps-return-value']; fails to actually return anything. Presumably it should be: return err['ps-return-value']; Daniel On Sun, Nov 14, 2010 at 5:44 PM, Vladimir Sedach <[email protected]> wrote: > Dammit, I was counting on being the lazy one. > > There's 6 different situations that block and return-from can be involved > in: > > 1. implicit nil block in iteration forms (do/dolist etc.) in lexical > extent: > > (ps (dolist (x '(1 2 3)) (when (= x 1) (return)))) > > => > > for (var x = null, _js_arrvar2 = [1, 2, 3], _js_idx1 = 0; _js_idx1 < > _js_arrvar2.length; _js_idx1 += 1) { > x = _js_arrvar2[_js_idx1]; > if (x === 1) { > break; > }; > }; > > 2. explicit nil or named block in lexical extent (we have to assign a > name to the nil block): > > (ps (block nil (return) (+ 1 2))) > > => > > nilblock: { > break nilblock; > 1 + 2; > }; > > 3. implicit named block established by defun, flet, and labels with > lexical extent: > > (defun foo () (return-from foo)) > > => > > function foo() { > return null; > }; > > 4. implicit named block established by defun, flet, and labels with > dynamic extent: > > (defun foo () ((lambda () (return-from foo)))) > > => > > function foo() { > try { > return (function () { > throw { 'ps-block-tag' : 'foo', 'ps-return-value' : null }; > })(); > } catch (err) { > if (err && 'foo' === err['ps-block-tag']) { > err['ps-return-value']; > } else { > throw err; > }; > }; > }; > > 5. explicit named block with dynamic extent: > > (block nil ((lambda () (return))) (+ 1 2)) > > => > > nilblock: { > try { > (function () { > throw { 'ps-block-tag' : 'nilblock', 'ps-return-value' : null }; > })(); > 1 + 2; > } catch (err) { > if (err && 'nilblock' === err['ps-block-tag']) { > err['ps-return-value']; > } else { > throw err; > }; > }; > }; > > 6. implicit nil block in iteration forms with dynamic extent return > > (ps (dolist (x '(1 2 3)) ((lambda (x) (when (= x 1) (return))) x))) > > => > > Which is currently not implemented > > Vladimir > > 2010/11/13 Daniel Gackle <[email protected]>: > > 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 <[email protected]> > 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 <[email protected]>: > >> > 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 <[email protected]> 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 <[email protected]> > >> >> 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 <[email protected]>: > >> >> >> 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 > >> >> >> [email protected] > >> >> >> http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel > >> >> >> > >> >> >> > >> >> > > >> >> > _______________________________________________ > >> >> > parenscript-devel mailing list > >> >> > [email protected] > >> >> > http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel > >> >> > > >> >> > >> >> _______________________________________________ > >> >> parenscript-devel mailing list > >> >> [email protected] > >> >> http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel > >> > > >> > > >> > _______________________________________________ > >> > parenscript-devel mailing list > >> > [email protected] > >> > http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel > >> > > >> > > >> > >> _______________________________________________ > >> parenscript-devel mailing list > >> [email protected] > >> http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel > > > > > > _______________________________________________ > > parenscript-devel mailing list > > [email protected] > > http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel > > > > > > _______________________________________________ > parenscript-devel mailing list > [email protected] > http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel >
_______________________________________________ parenscript-devel mailing list [email protected] http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
