Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change

Re: Smartmatch alternatives

by davido (Archbishop)
on Dec 17, 2013 at 15:26 UTC ( #1067483=note: print w/replies, xml ) Need Help??

in reply to Smartmatch alternatives

My problem with smartmatch is that it tries to replace several more explicit constructs. I prefer to just use the more explicit one, leaving less to heuristics. grep would be fine except for one problem; it does an exhaustive search. There's no (sane) way to tell it to stop searching after the first element meets the search criteria. I don't know if smartmatch stops after the first satisfying condition.

List::Util is a core Perl module. We should consider the functions it offers to be almost as much "first class citizens" as grep. ...except that for documentation we have to look at the module's POD rather than perldoc -f. One of its functions is any. This function stops searching immediately, and returns a true value as soon as one item meets the search criteria. And its name conveys exactly what it does; it's not searching for a whole bunch of things (like grep), it's just going to tell us whether any of the elements meet the criteria.

my $found = any { $_ eq 'something' } @array_of_strings; my $found = any { /\bsomething\b/ } @array_of_strings; my $found = any { $_ == 42 } @array_of_numbers; my $found = any { $_->isa('obj_type') } @array; my $found = any { $_->can('tupitar') } @array;

It's not as succinct as $something ~~ @array, but I can look at it and immediately know the semantics under which $something is being tested, whereas with smartmatch I have to open up perlop and check that my intuition isn't playing tricks on me.


Replies are listed 'Best First'.
Re^2: Smartmatch alternatives
by tobyink (Abbot) on Dec 17, 2013 at 19:22 UTC

    I agree with:

    "My problem with smartmatch is that it tries to replace several more explicit constructs. I prefer to just use the more explicit one, leaving less to heuristics."

    ... in most cases. Don't use ~~ when ==, eq or =~ would do a better job.

    However, there is one place I really miss smartmatch. Let's take for example RDF::RDB2RDF; you don't need to know all the details of what it does; suffice to say that it's got user-configurable objects which process a database. One of the options that can be configured is which tables (if any) should be skipped. I liked being able to say "set the ignore_tables option to anything that can be used as the right hand side of a smart match".

    So if they wanted to skip one particular table, they could do ignore_tables => "foo", if they had a list of tables to skip, then ignore_tables => \@private, or they could use a regexp ignore_tables => qr{^priv}, or if they had more complex requirements, ignore_tables => sub {...}.

    Smartmatch made implementing that really easy. And it's that aspect of smart match that made me want to write a stable replacement for it.

    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name
Re^2: Smartmatch alternatives
by LanX (Bishop) on Dec 17, 2013 at 15:56 UTC
    Agreed, but any is in List::MoreUtils (which isn't core. =)

    And XS and it's alternative pure Perl implementation was buggy last time I looked into it.


    oh did you mean first ? :)

    use List::Util qw(first max maxstr min minstr reduce shuffl +e sum); first BLOCK LIST ... "first" returns the first element where the result from BLOCK is a true value.


    grr @%$ !!!...

    DB<121> @a=0..10 => (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) DB<122> first { "0" eq $_ } @a => 0

    Cheers Rolf

    ( addicted to the Perl Programming Language)

      No, I meant List::Util::any.

      $ perl -MList::Util -E 'say "Yes" if List::Util::any { $_ == 42 } @{[q +w/1 3 42 5/]}' Yes

      It shows up in both modules. There may be subtle, undocumented differences.


        OK your CPAN- version doesn't show it in the synopsis

        SYNOPSIS use List::Util qw(first max maxstr min minstr reduce shuffle sum);

        and my 5.10 version does only list it as suggested.

        Anyway good news! (for me at least =)

        Cheers Rolf

        ( addicted to the Perl Programming Language)

        I see that it was added after 1.32 (most recent version installed here) ...

        1.33 -- Sun Oct 13 01:35 UTC 2013 * Added any, all, none, notall list reduction functions (inspired by List::MoreUtils)

      Well, L'U'first returns undef "[li]f BLOCK never returns true or LIST was empty" (as of version 1.32), so need to do check further if value is defined.

        so this should be a fast and core fallback if no better module available.

        DB<125> @a=(0)x10 => (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) DB<126> sub any (&@) { my $cr=shift; defined first { &$cr } @_ } DB<127> any {$_==0} @a => 1

        well could be faster if I could avoid '$cr' but my golfing foo is weak today. =)


        got it :)

        DB<138> sub any (&@) { defined &first (shift, @_) } DB<139> any {$_==0} @a => 1


        better :)

        DB<144> sub any (&\@) { defined &first } DB<145> any {$_==0} @a => 1


        DARN! still buggy with false positives!

        didn't sleep enough...


        this seems to work...

        DB<230> sub any (&@) { my $x=&List::Util::first; defined $x } DB<231> any { $_ eq 0 } @a => "" DB<232> any { $_ eq 5 } @a => 1 DB<233> @a => (1, 2, 3, 4, 5)

        Cheers Rolf

        ( addicted to the Perl Programming Language)

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: note [id://1067483]
and the shadows deepen...

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (2)
As of 2018-01-21 15:27 GMT
Find Nodes?
    Voting Booth?
    How did you see in the new year?

    Results (228 votes). Check out past polls.