Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Exception handling and "trap" vs. TRAPNAL()

    Hi Bart :)

 * Bart Schaefer <schaefer@xxxxxxxxxxxxxxxx> dixit:
> On Oct 3, 11:01am, DervishD wrote:
> }     I know, I know, but AFAIK the "always" block works more or less
> } the same as exception handling does in other languages.
> Less, not more.  The problem is that in a language with real
> exceptions, the difference between an error and an exception is
> well-defined, and it is usually possible to have errors without
> exceptions and vice-versa. Zsh's "always" block is an error
> handler, not an exception handler, and PWS's functions are
> overloading the meaning of "error".

    But always blocks handle errors that would cause the shell to
abort execution. In a certain way, they are exceptions, they're
different from errors (with "error" I mean the usual "non-zero exit
> } > }   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
> } 
> }     That's why I was quoting "return": I didn't mean a literal
> } "return" command, but a way of returning a value to the current code.
> Yes, but there *isn't* any way of returning a value to the surrounding
> code -- unless you mean something like setting $REPLY.  So your basis
> for the statement is a practical impossibility.

    I was thinking exactly that, using $REPLY or something similar. I
just wasn't sure if the trap restored all the environment or not.

> }     But if you propagate the error, you won't break such code. I
> } mean, even with your patch, this code...
> } 
> }     trap 'readonly VAR; VAR=0' ZERR
> } 
> }     print "HERE"
> }     false
> }     print "HERE AGAIN"
> } 
> }     ...will print both strings.
> In 4.0.6, or with my second potential patch, that prints only "HERE"
> (plus the error message about the readonly assignment).  In 4.2.5, it
> prints both strings.  In bash2, it also prints both strings.  Anything
> that relies on the 4.2.5 or bash2 behavior will break if we go back to
> propagating the error as was done in 4.0.6.

    It doesn't seem to be a good idea, then...
> } O:)) As far as I understan, "errflag" just signals the error and
> } propagate it to the current execution environment (for inline traps,
> } I mean), but doesn't make the shell abort :?
> It doesn't make the shell *exit*, but it does stop execution in the
> way that would jump into an "always" block.  (If it did not, how
> would it solve your problem?)  In the absence of the "always", it
> simply bails out of the current context.  The "always" block is a way
> to intercept the "bail out" action, but the bail-out happens whether
> "always" is there or not.

    OK, I just was assuming that without the always block the
execution would go on undisturbed, which is false. I don't know why I
got that false impression, because I really know that code like this:

    readonly VAR

    will stop execution. Sorry, my fault.
> }     If no patch is applied I can still use TRAPNAL's for throwing
> } exceptions, but I must think a way of doing that with inline traps,
> } which I think it's impossible because the value of TRY_BLOCK_ERROR is
> } reset.
> You're right, it's impossible.  You'll have to think about how you
> would write the code if you never had "always" in the first place,
> and write it that way.

    The problem is that I would like to use "always" blocks with the
"nonzeroexitcode" kind of errors (that's why I use ZERR, it helps me
to convert the normal errors into errors as defined in a try block
context, a condition which causes the shell to stop execution).
Obviously this doesn't need nor exceptions nor always blocks, a
simple "goto" will suffice because what I want is a way of avoiding
handling similar errors in a per-command basis. I mean, I want to
replace this code:

    command1 && {# handle here some possible error probably exiting}
    command2 && {# handle here exactly the same error as before}
    commandn && {# incredible, here we must handle a similar error}

    with this one:

    trap 'throw commonerror$LINENO' ZERR
    } always {
        # Here we catch and handle the common error
        #   In the exception name we have the line number,
        # just in case we want to fine tune error handling

    I face this kind of code frequently: some tightly coupled
commands that cause the same kind of errors, or whose failures can be
seen as a single error, and execution *must* stop at that point.

    That's the whole point. I maybe am using the wrong shell
construct for solving the problem, and obviously I can always use the
first syntax and handle errors one-by-one (and not, something like
this: { command1 || command 2 || command 3 } && {#handle error here}
won't always work for me), but I find the always block construct much
better for this task. If I cannot use the ZERR trap and I must add an
explicit throw call after each command, it still is far better than
handling the error in place, better even than using a function to
handle the error instead of the throw call, because of rethrowing.

    With all the information you've given to me, I think now that
it's not a good idea to patch zsh to alter current behaviour, because
I see that current behaviour makes sense, but nonetheless being able
to cause 'alwaysable' errors from inline traps looks very good to me

    Thanks again for all, Bart.

    Raúl Núñez de Arenas Coronado

Linux Registered User 88736 | http://www.dervishd.net
http://www.pleyades.net & http://www.gotesdelluna.net
It's my PC and I'll cry if I want to...

Messages sorted by: Reverse Date, Date, Thread, Author