=pod =for advent_year 2009 =for advent_day 19 =for advent_title The children were smartly dressed in matching attire for the holidays =for advent_author Jerrad Pierce Even though Santa's still stuck in the days of Perl 5.6, he too can have a little Perl 6 for Christmas with the magic of M. With M you get a a function called C—instead of a C<~~> operator—for all sorts of DWIMy equality testing. With it, we can implement a simple switch statement in our sample code to assign gifts based on kids' behavior: =begin pre nick@north# perl mod19.pl Bob gets a pony Zack gets a lump of coal Jerrad gets a pair of socks Eve gets a lump of coal Alice gets a pony =end pre Just for fun, Santa decided to try to run the Perl 5.10.0 tests for C<~~> with C and found that it passed 109 of 144 testsN. Not bad, but he noticed some patterns and after reading the documentation more carefully he discovered that many of the failures were due to the fact that the module had been written against A which debuted in 2002, and the relevant specification has since been superseded by A. After consulting A and making a few simple changesN, he was able to get an A> that only failed 5 tests: =begin pre nick@north# perl -Mlib=lib smartmatch_.t | & grep not not ok 5 - smart_match(\&foo, \&bar): 2 not ok 89 - smart_match([qw(1foo 2bar)], "2"): 1 not ok 90 - smart_match("2", [qw(1foo 2bar)]): 1 not ok 99 - smart_match(2, "2bananas"): 1 not ok 100 - smart_match("2bananas", 2): 1 =end pre The first failed test seems reasonable enough, since the tests are run in pairs, each with the operands in opposite order and of course C<&foo(\&bar)> is different from C<&bar(\&foo)>.N The other tests fail due to an apparent inconsistency in Perl 5.10. The tests are written to expect an I to match, even though C<2 == "2bananas"> and C<"2" == "2bar">N. So, with M you get a more useful tool than the native feature in 5.10. Indeed, even though the operand table for (the updated) M is more difficult to read than that of Perl 5.10, it also specifies an interesting behavior for objects: =begin pre OBJECT STRING $val1->can($val2) && $val1->$val2 =end pre i.e; smart match of an object and a string will invoke the object's method specified by the value of the string if available. Perl 5.10 on the other hand requires that C<~~> be overloaded to get any behavior beyond what is defined for arrays, hashes, scalars and regexps. One of the handy things about smart matching, is that it ignores one level of referencing so that C<\@a ~~ @a> is true, which could—for instance—allow you to handle subroutine arguments of greater variety with less code. Of course, since C doesn't work quite the same as C<@goodboys ~~ @badboys> since the arrays are flattened into a single list, you should instead pass referenced arguments like C.N =sourcedcode mod19.pl =begin footnote test This required a few modifications to F though: =sourcedcode smartmatch_t.patch =end footnote =begin footnote patch Santa's A includes corrections for the following changes between Apocalypse 4 and Synopsis 3: =over =item hash-hash key intersection → hash keys equality =item array-array intersection → array equality =item hash slice element truth → hash slice element existence =item array indexed value truth → array contains matching element =back and requires a A to get to only 5 failures. =end footnote =begin footnote commutative Somehow, the test passes in 5.10 though… =end footnote =begin footnote numish Numerical operations in Perl treat strings that begin with numbers as the leading number. This is why C<("0 but true" && "0 but true" == 0) == 1>. =end footnote =begin footnote prototype It's possible to get a C that I accept two arrays with prototypes, but C also needs to accept two hashes, a hash and an array, a hash and a scalar, etc. =end footnote =cut