Path: news.daimi.aau.dk!news.daimi.aau.dk!eernst From: eernst@fraxinus.daimi.aau.dk (Erik Ernst) Newsgroups: comp.lang.beta Subject: Re: nested patterns and leave/restart Date: 18 Aug 1995 20:03:11 GMT Organization: DAIMI, Computer Science Dept. of Aarhus Univ. Lines: 133 Message-ID: References: NNTP-Posting-Host: fraxinus.daimi.aau.dk In-reply-to: wpp@marie.physik.tu-berlin.de's message of 12 Aug 95 16:34:27 GMT In article wpp@marie.physik.tu-berlin.de (Kai Petzke) writes: Path: news.daimi.aau.dk!news.uni-c.dk!sunic!sunic.sunet.se!seunet!news2.swip.net!plug.news.pipex.net!pipex!tank.news.pipex.net!pipex!news.mathworks.com!fu-berlin.de!marie.physik.tu-berlin.DE!wpp From: wpp@marie.physik.tu-berlin.de (Kai Petzke) Newsgroups: comp.lang.beta Date: 12 Aug 95 16:34:27 GMT Lines: 69 NNTP-Posting-Host: marie.physik.tu-berlin.de (130.149.40.96) NNTP-Posting-User: wpp X-Access: 16 915 Summary: How to handle cases, where a leave/restart is executed out of place? Keywords: bug, leave, restart, pattern, nesting BETA implements the LEAVE and RESTART imperatives, which leave a block respective restart a block. It is possible, to use LEAVE and RESTART from blocks, that are nested within the block to leave respective restart. This yields an interesting problem, though, which is best demonstrated with a code example: ORIGIN '~beta/basiclib/v1.4/betaenv' ---program: Descriptor--- (# m: (# i: @integer enter i do 'p'->put; i->putint; newline #); f1: (# o: ^Object do l1: &(# do 1->m; leave l1; 2->m #)[]->o[] exit o[] #); f2: (# todo: ^Object enter todo[] do todo #); do f1->f2; 3->m #) This code compiles correctly with the Mjolner BETA system, but when run on linux, it just prints "p1", then crashes with a bus error. The problem is, that the object descriptor following the l1 label is not executed in place. Rather, an object is dynamically generated from that object descriptor, and executed later in a different environment. When the "leave l1" imperative is reached there, it is quite understandable, that this causes confusion to the run-time system. But this must be a Linux specific bug! When I compile your program on SunOS 5.4 (same as Solaris-2.5, I think, but "uname -a" says "SunOS"), I get: ---------------------------------------------------------------------- p1 # Beta execution aborted: Attempt to leave basic component. # Look at 'leave.dump' ---------------------------------------------------------------------- which is exactly your "2)" possibility: My question is to how expand the BETA language defintion to handle this particular case. I can right now think of the following two possibilities: 1) Forbid LEAVE and/or RESTART of enclosing blocks inside of patterns, that are not inserted items. 2) Allow LEAVE and/or RESTART also in non-safe places, like dynamically generated items or general attributes. When such an unsafe LEAVE/RESTART is encountered at run-time, the call stack is traversed to check, if an apopriate label can be found. If that is not the case, a runtime error occurs. [snip] And it is quite useful to be able to carry around a `bomb' that unrolls the stack to some specific level. I think of this as a safer version of C++ style exception handling: When _creating_ such a beast, you always do it in connection with a specific label, so there is a static aspect; this is absent in C++ where "throw SomeObject" has absolutely no static `home' to search for when unrolling the stack. On the other hand both approaches have the possibility to unroll the stack all the way down to the bottom, and this must be a run-time error. Just like "Reference-is-NONE", it's undecidable whether this condition can arise for programs in general. Here is an example from working code where a number "NBscopes" can be executed in a nested fashion at run-time (something that is an NBscope (or specialization thereof) executes something that executes something ... that is an NBscope (or spec.) etc.) and an operation "leaveNBscope" is always guaranteed to unroll the stack until the outermost "NBscope". It's taken from a more complex context---I hope it's possible to make sense of it as-is (the enclosing object has a `private' that holds the `untryPatVar' that is set to register the outermost NBscope with respect to that object): ---------------------------------------------------------------------- NBscope: (# do tryLabel: (# doUntry: (# do (* Leaving: always "deactivate" *) NONE -> private.untryPatVar##; leave tryLabel #); do (if private.untryPatVar##//NONE then (* Outermost NBScope: "activate" *) doUntry## -> private.untryPatVar##; INNER NBscope; NONE -> private.untryPatVar##; else (* Nested NBScope: "is active" *) INNER NBscope; if); #); #); leaveNBscope: (# do (if private.untryPatVar## <> NONE then private.untryPatVar if); #); ---------------------------------------------------------------------- Now, how would you do that in the C++ (and SML) model for exceptions? ciao, -- Erik Ernst eernst@daimi.aau.dk Computer Science Department of Aarhus University, Denmark