My Favorite Warnings: exiting

Perl has various ways to transfer control out of the normal flow: die(), goto(), return(), next, last, and redo are among the sorts of things I mean. Not all of these are suitable for all circumstances, and Perl issues an exiting warning for unsuitable cases.

Sometimes, though, you just need to do something unsuitable. When I write an interactive script, it generally dispatches to a subroutine named after the function, something like so:

while ( defined( my $line = $term->readline( 'prompt> ' ) ) ) {
    my ( $cmd, @arg ) = shellwords( $line );
    if ( my $code = __PACKAGE__->can( "cmd_$cmd" ) ) {
        $code->( @arg );
    } else {
        warn "Unknown command $cmd\n";
    }
}

I find this very handy; if I want to add a command, all I have to do is write a subroutine. But when I write sub cmd_exit{ ... }, it is not clear what goes inside the subroutine. The "proper" implementation is probably to have cmd_exit(), and only that subroutine, return a code that means it's time to exit the loop, and then test the return code and act appropriately. Suddenly the code got a little more complicated.

When refactoring a chained if ( ... ) { ... } elsif ( ... ) ... implementation into subroutines, I stumbled across the fact that you can, in fact, exit a subroutine with last. Perl warns about it, because it is not at all the usual way to do things. But it will work, and the implementation of the exit command becomes

sub cmd_exit {
    no warnings qw{ exiting };
    last;
}

The cautious programmer may wish to label the main loop and specify that label in the last statement.

Notes relevant to the code samples, but irrelevant to the warning being discussed:

  • The script samples assume $term is a Term::ReadLine object, and that shellwords() comes from Text::ParseWords.
  • A more useful example of the above dispatch loop will guard against empty lines ($cmd is undef) and comments, however defined.
  • The dispatch loop might also want to execute $code->( @arg ) inside an eval { ... }.
  • The problem with sub cmd_exit { exit } is that any cleanup after the dispatch loop does not get done. Time for "My Favorite Scheduled Blocks?"

Previous entries in this series:

  1. once
  2. redundant and missing

2 Comments

I do not trigger it ever, even do not know it exists, thank you :)

This series has been interesting. Thanks for that.

Plus, TIL about `Text::ParseWords`. Double thanks!

Leave a comment

About Tom Wyant

user-pic I blog about Perl.