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
code").
 
> } > }   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
    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
    {
        command1
        command2
        command3
    } 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
O:))

    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