The new smart match dispatch table for 5.10.1 onwards
Rafael Garcia-Suarez [Wed, 4 Mar 2009 20:14:10 +0000 (21:14 +0100)]
This /does/ break backwards compatibility. Changes to come are:

- ~~ is no longer commutative. Dispatch is now done based on the
  (run-time) type of the right side argument.
- The right side can be a ".." range, which will be treated specially,
  and no longer as a boolean operator (as in scalar context).
- when() should treat "..." as a boolean operator.
- Coderefs with an empty prototype are no longer special.
- Any ~~ Array distributes the smart match test.
- Comparing two coderefs is no longer a special case and does not
  perform referential equality. (Use \&foo ~~ "".\&bar for that.)

This patch also documents that ~~ won't work on objects that don't
overload it, except in the expression $object ~~ undef.

pod/perlsyn.pod

index 56b65d5..2e1f4c5 100644 (file)
@@ -588,6 +588,11 @@ exclusive-or C<(...) xor (...)>.
 a filetest operator, with the exception of C<-s>, C<-M>, C<-A>, and C<-C>,
 that return numerical values, not boolean ones.
 
+=item *
+
+the C<...> flip-flop operator (but B<not> the two-dot version C<..>, which
+is used to construct and test against numerical or string ranges).
+
 =back
 
 In those cases the value of EXPR is used directly as a boolean.
@@ -665,47 +670,55 @@ variable C<$_>. (You can use C<for my $_ (@array)>.)
 
 =head3 Smart matching in detail
 
-The behaviour of a smart match depends on what type of thing
-its arguments are. It is always commutative, i.e. C<$a ~~ $b>
-behaves the same as C<$b ~~ $a>. The behaviour is determined
-by the following table: the first row that applies, in either
-order, determines the match behaviour.
-
+The behaviour of a smart match depends on what type of thing its arguments
+are. The behaviour is determined by the following table: the first row
+that applies determines the match behaviour (which is thus mostly
+determined by the type of the right operand). Note that the smart match
+implicitly dereferences any hash or array ref, so the "Hash" and "Array"
+entries apply in those cases.
 
     $a      $b        Type of Match Implied    Matching Code
     ======  =====     =====================    =============
-    (overloading trumps everything)
+    Any     undef     undefined                !defined $a
+
+    (overloading trumps everything below)
 
-    Code[+] Code[+]   referential equality     $a == $b
-    Any     Code[+]   scalar sub truth         $b->($a)
+    Hash    CodeRef   sub truth for each key   !grep { !$b->($_) } keys %$a
+    Array   CodeRef   sub truth for each elt   !grep { !$b->($_) } @$a
+    Any     CodeRef   scalar sub truth         $b->($a)
 
     Hash    Hash      hash keys identical      [sort keys %$a]~~[sort keys %$b]
+    Array   Hash      hash slice existence     @$a == grep {exists $b->{$_}} @$a
+    Regex   Hash      hash key grep            grep /$a/, keys %$b
+    undef   Hash      always false (undef can't be a key)
+    Any     Hash      hash entry existence     exists $b->{$a}
+
     Hash    Array     hash slice existence     @$b == grep {exists $a->{$_}} @$b
-    Hash    Regex     hash key grep            grep /$b/, keys %$a
-    Hash    Any       hash entry existence     exists $a->{$b}
+    Array   Array     arrays are comparable[1]
+    Any     Array     match against an array element[2]
+                                               grep $a ~~ $_, @$b
 
-    Array   Array     arrays are identical[*]
+    Hash    Regex     hash key grep            grep /$b/, keys %$a
     Array   Regex     array grep               grep /$b/, @$a
-    Array   Num       array contains number    grep $_ == $b, @$a
-    Array   Any       array contains string    grep $_ eq $b, @$a
-
-    Any     undef     undefined                !defined $a
     Any     Regex     pattern match            $a =~ /$b/
-    Code()  Code()    results are equal        $a->() eq $b->()
-    Any     Code()    simple closure truth     $b->() # ignoring $a
-    Num     numish[!] numeric equality         $a == $b
+
+    Num     Range[3]  in numeric range
+    undef   Range[3]  always false
+    Any     Range[3]  in string range
+
+    Num     numish[4] numeric equality         $a == $b
     Any     Str       string equality          $a eq $b
     Any     Num       numeric equality         $a == $b
-
     Any     Any       string equality          $a eq $b
 
 
- + - this must be a code reference whose prototype (if present) is not ""
-     (subs with a "" prototype are dealt with by the 'Code()' entry lower down)
- * - that is, each element matches the element of same index in the other
-     array. If a circular reference is found, we fall back to referential
-     equality.
- ! - either a real number, or a string that looks like a number
+ 1 - that is, each element matches the element of same index in the other
+     array. [2]
+ 2 - If a circular reference is found, we fall back to referential equality.
+ 3 - a range is written EXPR..EXPR (using the C<..> range operator, but
+     NOT the three-dot version C<...>, which will be treated as a boolean
+     operator)
+ 4 - either a real number, or a string that looks like a number
 
 The "matching code" doesn't represent the I<real> matching code,
 of course: it's just there to explain the intended meaning. Unlike
@@ -717,6 +730,11 @@ You can change the way that an object is matched by overloading
 the C<~~> operator. This trumps the usual smart match semantics.
 See L<overload>.
 
+It should be noted that C<~~> will refuse to work on objects that
+don't overload it (in order to avoid relying on the object's
+underlying structure). The only exception is when testing for
+definedness with C<$object ~~ undef>.
+
 =head3 Differences from Perl 6
 
 The Perl 5 smart match and C<given>/C<when> constructs are not