http://www.perlmonks.org?node_id=1039456

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

I've been reading the Perl 5.18 delta, and now that smartmatch is both experimental and depreciated I'm in a bit of a muck. I have a big project that uses given/when quite heavily (28 givens, 85 whens).

What is the recommended way to fix this? I know I can turn off the warning, but I'd rather fix the code. The documentation says that given/when is subject to big changes and might even go away, so disabling the warning is only a temporary fix. An automatic fix would be nice, but I don't mind doing all the work by hand. I have a good test suite, so I'm not concerned about breaking things.

Mostly the given/whens look like this:

given($foo) { when('abc') {...} when(['foo', 'bar']) {...} default {...} };

Replies are listed 'Best First'.
Re: Smart matching is experimental/depreciated in 5.18 - recommendations?
by ikegami (Patriarch) on Jun 17, 2013 at 20:54 UTC

    Let's start with some background as to what's going on.

    There are problems with the implementation. The decision of what any given TYPE ~~ TYPE should do is most often unobvious, inconsistent and/or disputed. The idea isn't to remove smart matching; it's to fix it.

    Specifically, ~~ will be greatly simplified, as you can see in a proposal by the 5.18 pumpking. Decisions as to how two things should match will be done with helpers such as those that already exist in Smart::Match.

    ... ~~ any(...)

    Much more readable, much more flexible (fully extensible), and solves a number of problems (such as "When should X be considered a number, and when should it be considered a string?").

    So, if you like the feel of given+when, I recommend that you use experimental to disable the warnings and convert your code to use Smart::Match. Smart::Match uses overloaded objects and/or code refs, and that will continue to be supported. I'm hopeful that Smart::Match will be updated if necessary should the details change.

Re: Smart matching is experimental/depreciated in 5.18 - recommendations?
by tobyink (Canon) on Jun 17, 2013 at 19:45 UTC

    Here's a few roads you could go down...

    • experimental - can be used to simply disable the warning
    • Switch::Plain - a module providing a simple switch statement, but just using eq/== and not smart match
    • match::smart - a pure perl implementation of the logic of smart match, but not the smart match syntax
    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
Re: Smart matching is experimental/depreciated in 5.18 - recommendations?
by BrowserUk (Patriarch) on Jun 17, 2013 at 20:18 UTC

    You could take a look at Switch::Perlish. It doesn't use source filters like the deprecated Switch and it does do some (many) forms of 'smart matching' -- though how well they correspond to the now deprecated in-built smart-matching I have no idea.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Smart matching is experimental/depreciated in 5.18 - recommendations?
by LanX (Saint) on Jun 17, 2013 at 20:53 UTC
    I prefer good old for-if over given-when constructs, since I never really trusted ~~

    You just have to add next at the end of each case to avoid fall-through.

    See following thread for details:

    Understanding the benefit of Given/When ...

    FWIW I wouldn't miss most of smart-match, except the in feature to test scalar inclusion in a list.

    $scalar ~~ [ LIST ]

    seems like I need to abstract it into an in function for future compatibility...

    Cheers Rolf

    ( addicted to the Perl Programming Language)

      > You just have to add next at the end of each case to avoid fall-through.

      or use classic elsif chains

      $\="\n"; for (qw/abc foo bar 42 unknown/) { if (/^abc$/) { print 'abc'; } elsif (/^(foo|bar)$/) { print "foo bar"; } elsif ( $_ eq 42 ) { print "42"; } else { print "default: $_"; } } __END__ abc foo bar foo bar 42 default: unknown

      if you don't like regex define a sub in to do the test

      $\="\n"; sub in { $_ ~~ $_[0] } for (qw/abc foo bar 42 unknown/) { if ( in ['abc']) { print 'abc'; } elsif ( in [qw/foo bar/] ) { print "foo bar"; } elsif ( in [42] ) { print "42"; } else { print "default: $_"; } } __END__ abc foo bar foo bar 42 default: unknown

      since the smart match is abstracted away you have maximum freedom to change/fallback implementation of in to regex or even a memoized hash.

      Cheers Rolf

      ( addicted to the Perl Programming Language)

Re: Smart matching is experimental/depreciated in 5.18 - recommendations?
by LanX (Saint) on Jun 17, 2013 at 21:51 UTC
    FWIW if performance matters and string equality is sufficient you can use goto EXPR

    $\="\n"; for my $foo (qw/abc foo bar 42 unknown/) { eval {goto "_$foo"} or do { print "default"; next; }; _abc: print 'abc'; next; _foo: ; _bar: print "foo bar"; next; _42: print "42"; next; } __END__ abc foo bar foo bar 42 default

    plz note, leading underscores only needed for numeric cases...

    I don't recommend this over simple if/elsif constructs if performance doesn't matter.

    Cheers Rolf

    ( addicted to the Perl Programming Language)

Re: Smart matching is experimental/depreciated in 5.18 - recommendations?
by kcott (Archbishop) on Jun 18, 2013 at 14:03 UTC

    G'day coolmichael,

    Another potential option is to use nested ternary (?:) operators. Here's an example using your "Mostly the given/whens look like this" construct:

    $ perl -Mstrict -Mwarnings -E ' use 5.018; no if $] >= 5.018, warnings => "experimental::smartmatch"; my @tests = qw{abc bar def foo}; say "*** Using given/when ***"; for my $foo (@tests) { given ($foo) { when ("abc") { say "$foo = exact match" } when (["foo", "bar"]) { say "$foo = list match" } default { say "$foo = no match" } } } say "*** Using nested ternary ***"; for my $foo (@tests) { say "$foo = ", ( $foo eq "abc" ? "exact" : grep($foo eq $_, ("foo", "bar")) ? "list" : "no" ), " match"; } ' *** Using given/when *** abc = exact match bar = list match def = no match foo = list match *** Using nested ternary *** abc = exact match bar = list match def = no match foo = list match

    Update: s/-Mstrict -Mstrict/-Mstrict -Mwarnings/

    -- Ken

Re: Smart matching is experimental/depreciated in 5.18 - recommendations?
by sundialsvc4 (Abbot) on Jun 18, 2013 at 17:52 UTC

    What I would do, frankly, is to replace that code with something else, and not use that “sugary” feature again.   Probably, I would simply use a if..elsif..else chain.   Another technique is to set up a hash-table containing code references to handler subroutines, if you really needed to.   I have shunned the use of the feature because it really does not add semantic meaning to the language, and now, to hear that it is “subject to big changes or maybe even going away,” I would feel justified in that cautious decision.   (Gee, that didn’t last long.)   Long-term maintainable code should be averse to the blowing wind of passing fancies.