From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 1519 invoked from network); 3 Oct 2005 01:38:29 -0000 Received: from news.dotsrc.org (HELO a.mx.sunsite.dk) (130.225.247.88) by ns1.primenet.com.au with SMTP; 3 Oct 2005 01:38:29 -0000 Received: (qmail 15332 invoked from network); 3 Oct 2005 01:38:17 -0000 Received: from sunsite.dk (130.225.247.90) by a.mx.sunsite.dk with SMTP; 3 Oct 2005 01:38:17 -0000 Received: (qmail 19923 invoked by alias); 3 Oct 2005 01:38:15 -0000 Mailing-List: contact zsh-workers-help@sunsite.dk; run by ezmlm Precedence: bulk X-No-Archive: yes X-Seq: 21806 Received: (qmail 19914 invoked from network); 3 Oct 2005 01:38:14 -0000 Received: from news.dotsrc.org (HELO a.mx.sunsite.dk) (130.225.247.88) by sunsite.dk with SMTP; 3 Oct 2005 01:38:14 -0000 Received: (qmail 15049 invoked from network); 3 Oct 2005 01:38:14 -0000 Received: from vms048pub.verizon.net (206.46.252.48) by a.mx.sunsite.dk with SMTP; 3 Oct 2005 01:38:12 -0000 Received: from candle.brasslantern.com ([71.116.81.225]) by vms048.mailsrvcs.net (Sun Java System Messaging Server 6.2 HotFix 0.04 (built Dec 24 2004)) with ESMTPA id <0INR001RYGJBZTB1@vms048.mailsrvcs.net> for zsh-workers@sunsite.dk; Sun, 02 Oct 2005 20:38:01 -0500 (CDT) Received: from candle.brasslantern.com (IDENT:schaefer@localhost [127.0.0.1]) by candle.brasslantern.com (8.12.11/8.12.11) with ESMTP id j931bxLQ003111; Sun, 02 Oct 2005 18:37:59 -0700 Received: (from schaefer@localhost) by candle.brasslantern.com (8.12.11/8.12.11/Submit) id j931bw45003110; Sun, 02 Oct 2005 18:37:58 -0700 Date: Mon, 03 Oct 2005 01:37:57 +0000 From: Bart Schaefer Subject: Re: Exception handling and "trap" vs. TRAPNAL() In-reply-to: <20051002230027.GA194@DervishD> To: DervishD Cc: zsh-workers@sunsite.dk Message-id: <1051003013758.ZM3107@candle.brasslantern.com> MIME-version: 1.0 X-Mailer: Z-Mail (5.0.0 30July97) Content-type: text/plain; charset=iso-8859-1 Content-transfer-encoding: quoted-printable References: <20050929200741.GA1156@DervishD> <20050930124130.45eb0463.pws@csr.com> <20051001153756.GA12183@DervishD> <1051001183818.ZM27904@candle.brasslantern.com> <20051001202856.GA134@DervishD> <1051002044052.ZM28373@candle.brasslantern.com> <20051002190940.437F9866F@pwstephenson.fsnet.co.uk> <1051002195518.ZM2163@candle.brasslantern.com> <20051002230027.GA194@DervishD> Comments: In reply to DervishD "Re: Exception handling and "trap" vs. TRAPNAL()" (Oct 3, 1:00am) X-Spam-Checker-Version: SpamAssassin 3.0.4 (2005-06-05) on f.primenet.com.au X-Spam-Level: X-Spam-Status: No, score=-2.5 required=5.0 tests=AWL,BAYES_00 autolearn=ham version=3.0.4 Having written most of what follows, I just discovered something that may make a lot of it moot: In zsh prior to 4.1.something, an error condition in an inline trap *WAS* passed through to the calling context. That it now is not, is apparently either a broken behavior or an undocumented change, and in any case no code written for older zsh could have relied upon errors in traps being inconsequential. Compare zsh-4.0.6: schaefer[505] trap 'readonly BAR; BAR=3D ; print ok' ZERR schaefer[506] foo() { false; print more } schaefer[507] foo foo: read-only variable: BAR schaefer[508] print $? 1 Now here's zsh-4.2.5: schaefer[501] trap 'readonly BAR; BAR=3D ; print ok' ZERR schaefer[502] foo() { false; print more } schaefer[503] foo foo: read-only variable: BAR more schaefer[504] print $? 0 This gets even stranger if you compare to bash2. With an ERR trap, bash2 behaves like zsh-4.2.5 (except that the ERR trap is reset on function entry, so you have to put the trap command inside the body). So maybe this is a standards-compliance thing? [ASIDE: The bash2 behavior implies that traps set globally outside of a function are not supposed to apply within the function context. E.g., in bash2 a global INT trap does not prevent the function from being interrupted by a SIGINT; instead it handles the signal in the context where the trap command was run. Similarly an ERR trap stops being tripped during the body of the function, but remains in effect so that it is tripped if/when the function itself returns nonzero. This is, almost, the inverse of zsh's "setopt localtraps" behavior.] Nevertheless ... On Oct 3, 1:00am, DervishD wrote: } } I insist: while ZERR may not be the place for throwing exceptions } (I think it's a perfect place, but that's another matter), signals } like SIGTERM, SIGINT, etc. or even SIGALRM, are very good candidates } to do exception handling. Ra=FAl ... the important point that you're missing is that zsh doesn't really have or handle exceptions. Peter's throw/catch functions are simulations of exception behavior using a mechanism that is far less powerful than true exception handling. The zsh "always" syntax could -- and perhaps even should -- have been implemented equally well as a new syntax for the "eval" builtin, much like Perl's "eval" can be followed by a curly-bracketed block instead of a string. Zsh's TRY_BLOCK_ERROR is a crude approximation of Perl's $@, in that $TRY_BLOCK_ERROR captures only the presence of an error and not the error message. (In fact, a very useful extension would be to add an EVAL_ERROR variable that is 1 if an "eval" stopped with an error, and 0 if "eval" finished normally, so that an error could be distinguished from "eval false".) The important distinction, though, is that zsh lacks even an approximation of Perl's "die" builtin. } Propagating "errflag" may break current code only if that code is } using an inline trap which "returns" a value and that error value is } ignored on purpose. That's not quite correct. Remember, an inline trap using the "return" builtin actually causes the surrounding/calling context to return, so it's imposible to provide a value to the calling context that way; "return" in an inline trap is roughly analogous to using "break 2" in a nested loop. When "return" is not used, the value of $? from the calling context is always restored when the trap finishes, so it never makes sense for the calling context to expect to get a value from an inline trap. } Of course, there are other code that may break: inline traps } which generate syntax errors [...] that } previously didn't cause any problem except maybe print an error } message and now will jump into the "always" block. But I don't think } there is much code out there using "always" blocks that can break. The trouble is not with code that is using an "always" block, it's with code that is NOT using an "always" block. Which would be the majority of existing code, because "always" is a very new feature. So propagating errflag may break current code if that code is using an inline trap, that code does not have an "always" block, and that code expects to keep going no matter what happens in the trap. } I cannot think about any other code that may break due to the } last change you're proposing, but anyway your first patch seems } reasonable too: if inline traps cannot throw exceptions, do not let } function traps do it and document the problem (not about exceptions, } but about return values and syntax errors). Here's another way to think about it: Presently (that is, without either of my patches), a TRAPNAL function handles error conditions like a function call, whereas an inline trap handles error conditions like an "eval" statement. That's defensible, in a way, because a "trap" command *looks* like an "eval" statement; it contains a string that is evaluated as commands. It could even be explained that way in the docs, so that you would have understood why your sample script didn't work. Given all of this plus the bash2 behavior, I'm inclined to add a few more words to the documentation and apply *neither* of the patches from workers/21804. Further, *IF* we were going to choose one of those patches to apply, I'd say it should be the first one, to make TRAPNAL ignore errors too. Here's how to use throw/catch from a TRAPNAL function in the event that 21804 part 1 is applied: TRAPZERR() { eval 'throw DEFAULT'; return 1 } That is, call throw in the eval to set the variables, and then return a positive $? to interrupt into the always block.