Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl Monk, Perl Meditation
 
PerlMonks  

'switch' and 'smartmatch' features deprecated in 5.38

by ibm1620 (Hermit)
on Jun 25, 2023 at 16:53 UTC ( [id://11153110] : perlquestion . print w/replies, xml ) Need Help??

ibm1620 has asked for the wisdom of the Perl Monks concerning the following question:

Dear monks,

I'm playing with perl-5.38.0-RC2 and my given / when statements are all receiving deprecation warnings. As explained in the perldelta :

The "switch" feature and the smartmatch operator, ~~, were introduced in v5.10. Their behavior was significantly changed in v5.10.1. When the "experiment" system was added in v5.18.0, switch and smartmatch were retroactively declared experimental. Over the years, proposals to fix or supplement the features have come and gone.

In v5.38.0, we are declaring the experiment a failure. Some future system may take the conceptual place of smartmatch, but it has not yet been designed or built.

These features will be entirely removed from perl in v5.42.0.

I use feature 'switch' and given / when in my program template for processing Getopt::Std options, which means it's everywhere.

#!/usr/bin/env perl use v5.36; use Getopt::Std; use feature qw/switch/; no warnings q/experimental::for_list/; sub HELP_MESSAGE { ...; exit } my $verbose; my $force; my $table; my %opts; HELP_MESSAGE() if !getopts( 'hvft:', \%opts ); for my ( $k, $v ) (%opts) { given ($k) { when ('h') { HELP_MESSAGE(); } when ('v') { ++$verbose; } when ('f') { ++$force; } when ('t') { $table = $v; } default { die "*** BUG: no handler for -$k.\n"; } } }
It looks like I can safely replace "given" with "for" to bind the topic variable. The "when" statement provided a concise way to test the topic, but since that's going away, is this the most concise way to write it?
for my ( $k, $v ) (%opts) { if ( $k eq 'h' ) { HELP_MESSAGE(); } elsif ( $k eq 'v') { ++$verbose; } elsif ( $k eq 'f') { ++$force; } elsif ( $k eq 't') { $table = $v; } else { die "*** BUG: no handler for -$k.\n"; } }
Thanks!

Replies are listed 'Best First'.
Re: 'switch' and 'smartmatch' features deprecated in 5.38
by ikegami (Patriarch) on Jun 25, 2023 at 17:05 UTC
    when ( 'h' ) { ... }
    could also be replaced with
    if ( $k eq 'h' ) { ...; next }

    Makes it more tail-heavy than head-heavy.


    In this case, this could be cleaned up by using Getopt::Long.

    use Getopt::Long qw( GetOptions ); Getopt::Long::Configure(qw( posix_default )); GetOptions( 'help|h|?' => \&help, 'verbose|v' => \my $verbose, 'force|f' => \my $force, 'table|t=s' => \my $table, ) or usage(); @ARGV == 0 or usage( "Too many arguments" );

    Sample help and usage:

    use File::Basename qw( basename ); sub help { my $prog = basename( $0 ); print "Usage: $prog [options] $prog --help Options: --verbose -v ... --force -f ... --table {table} -t {table} ... "; exit( 0 ); } sub usage { if ( @_ ) { my ( $msg ) = @_; chomp( $msg ); say STDERR $msg; } my $prog = basename( $0 ); say STDERR "Try '$prog --help' for more information."; exit( 1 ); }
Re: 'switch' and 'smartmatch' features deprecated in 5.38
by tobyink (Canon) on Jun 26, 2023 at 07:12 UTC

    This is a little more concise, I guess:

    $opts{h} and HELP_MESSAGE(); $opts{v} and ++$verbose; $opts{f} and ++$force; $opts{t} and $table = $opts{t}; die "*** BUG: no handler for -$_.\n" for grep !/^[hvft]$/, keys %opts;

      shouldn't each of $opts{...} and be prefixed with exists?

      Optimising for fewest key strokes only makes sense transmitting to Pluto or beyond

        Only the "$opts{t} and $table = $opts{t};" line as the rest rely on a true value.

      I guess for sheer conciseness this would work:
      for ( keys %opts ) { /h/ ? HELP_MESSAGE() : /v/ ? ++$verbose : /f/ ? ++$force : /t/ ? $table = $opts{$_} : die "*** BUG: no handler for -$_.\n"; }

        Although one should first check the keys are all single letter for this case, otherwise one will get matches for words like haft, vatful and thrive.

      I like how that eliminates looping.
Re: 'switch' and 'smartmatch' features deprecated in 5.38
by eyepopslikeamosquito (Archbishop) on Jun 26, 2023 at 00:18 UTC
Re: 'switch' and 'smartmatch' features deprecated in 5.38
by NERDVANA (Deacon) on Jun 27, 2023 at 01:15 UTC
    Like ikegami, I recommend Getopt::Long. I also recommend combining it with Pod::Usage. It results in very little boilerplate for a very robust and extensible design.

    use Pod::Usage; use Getopt::Long; Getopt::Long::Parser->new(config => ['gnu_getopt']) ->getoptions( 'help|h' => sub { pod2usage(1) }, 'man' => sub { pod2usage(-exitval => 1, -verbose => 2) }, 'verbose|v' => \my $verbose, 'force|f' => \my $force, 'table=s' => \my $table, ) or pod2usage(2);

    Give it a try.

        Well, not exactly preaching to the choir if ibm1620 wasn't using Getopt::Long and ikegami didn't mention Pod::Usage. But, I know I'm not the first to suggest it of course.

        Then, there's the other faction who insist that MooseX::(something) should be used to automatically generate the commandline options. I've experimented with those and found them lacking, because command lines are inherently a thing meant to be human-friendly and I always seem to want to add some special case that the MooX::... and MooseX::... modules can't support. Getopt::Long has always given me the tools I needed to get that done. So, after lots of experimentation, I always come back to Getopt::Long and Pod::Usage. I basically consider the pair to be the only right way to start a perl script.