in reply to Re: 'finally' block in Perl?
in thread 'finally' block in Perl?

Why do you have two layers of { curly braces } delimiting the eval block?

Replies are listed 'Best First'.
Re^3: 'finally' block in Perl?
by haukex (Archbishop) on Jan 06, 2019 at 16:21 UTC

    perlsyn describes how last, redo, or next won't work (or won't do what one might expect) in if, unless, do{}, sub{}, and eval{}. last says: "Note that a block by itself is semantically identical to a loop that executes once. Thus last can be used to effect an early exit out of such a block." - a solution also described in perlsyn: "Loop control statements don't work in an if or unless, since they aren't loops. You can double the braces to make them such, though. ... This is caused by the fact that a block by itself acts as a loop that executes once".

    Update: Note how in the following, the first part prints "A" and "B" (and a warning about exiting eval via last), but not "D", while the second part prints "X", "Y", and "Z".

    { print "A\n"; eval { print "B\n"; last; print "C\n"; }; print "D\n"; } { print "W\n"; eval {{ print "X\n"; last; print "Y\n"; }}; print "Z\n"; }
      Ah right, because the original question wanted to support multiple return places. Thank you for the detailed reply! I also realized that the first reply called it a "bare block" which I could have used to do a Google search had I read it more carefully. I found this when looking for a way to handle clean-up in a function that may exit early due to an exception, not a return. In my case, the "eval" approach (without the bare block) with a "die $@ if $@" is satisfactory so I don't have to pull in an extra dependency. Hypothetically, the "early return" case can be handled by wrapping early-returnable logic in a separate function, though I can see that this may be cumbersome in some contexts.
        die $@ if $@

        Be careful with that, see Bug in eval in pre-5.14 - the better pattern is eval { ...; 1 } or do { handle_error() };

        Hypothetically, the "early return" case can be handled by wrapping early-returnable logic in a separate function, though I can see that this may be cumbersome in some contexts.

        There are several different ways to handle a kind of "return early but perform cleanup" in Perl, which one is most applicable depends on the situation (e.g. simple control flow, as you said using a separate function, the code shown in this thread, finally from a module like Try::Tiny, End, ...). If I were to use the bare block with last method, personally I'd prefer to label the block to make it absolutely clear where the last will jump to, and make it immune to accidentally adding in another bare block:

        { print "A\n"; FOO: { print "B\n"; { last FOO; print "C\n"; } print "D\n"; } # last jumps here print "E\n"; }