develooper Front page | perl.perl5.porters | Postings from January 2008

Clarifying smart match behaviour in when( ... && ... )

Thread Next
brian d foy
January 29, 2008 19:20
Clarifying smart match behaviour in when( ... && ... )
Message ID:


I'm trying to figure out when() using smart-matching combined
with logical operators for the next edition of Learning Perl.

For a little background: perlsyn notes that there are exceptions
to smart matching in when():

   * a subroutine call
   * a regex using $_ by default (which is a smart match, btw)
   * a regex expliclty bound to a variable (negated, even)
   * an explicit comparison
   * defined(), exists(), or eof()
   * a negated expression (!, not)
   * an xor

Right after that bit in perlsyn, it talks about &&.

   If EXPR is ... && ... or ... and ... , the test is applied
   recursively to both arguments. If both arguments pass the
   test, then the argument is treated as boolean.

That last sentence is weird. If both arguments pass the test,
it's treated as boolean. What does that imply if one or both
don't pass the test? And, is "test" just "one of the previously
listed exceptions".

So, the example I was playing with wanted to check if a value was
in an array and also the key of a hash:

   given( $foo ) {
      when( @n && %n ) { ... }
Since neither of the arguments are one of the exceptions, I
expected both arguments to be treated as a smart match:

   given( $foo ) {
      when( $_ ~~ @n && $_ ~~ %n ) { ... }

Now, nothing in the docs say that should be the case, so before I
do too much work in going through the other odd situations I
found, I figure I'll check if it's a doc problem first or if I'm
being a lunkhead.

Here's what I think the docs are trying to say, and once we get
this right (which might mean correcting my thinking and
documenting it better) I can think about the rest of it:

   If EXPR is ... && ... or ... and ..., and both of the
   arguments are one of the listed exceptions, Perl treats both
   arguments as booleans and performs no smart matching. If only
   one of the arguments is one of the exceptions, Perl treats
   that argument as a boolean and performs a smart match with
   the other argument. If neither argument is one of the
   exceptions, Perl performs a separate smart match with each

However, I don't know how to square the statement with a test in
t/op/switch.t. I think the test comment might be wrong. Should
there be a smart match that fails in the first when(), which is
why it moves onto the second? If so, the comment should say
something like "((1 == 1) && \"bar\") used smart match and fails
like it should".

   # t/op/switch.t
      my $ok = 1;
      given("foo") {
      when((1 == 1) && "bar") {
         $ok = 0;
      when((1 == 1) && $_ eq "foo") {
         $ok = 2;
      is($ok, 2, "((1 == 1) && \"bar\") not smartmatched");

I'll happily add some more tests once I know what the answers should
be. :)

Here's a program I was playing with, and the output I got that led me
to all of this. 


use 5.010;

my @n = qw(0 Barney Wilma);
my %n = map { $_, 1 } @n;

$\ = "\n\t";

for( '', qw(0 1 Barney) )
   my $n  = $_;

   say "\nProcessing [$n]...";
   when( %n  )      
      { say "1. In \%n";   continue } # $_ ~~ %n
   when( @n  )      
      { say "2. In \@n";   continue } # $_ ~~ @n
   when( @n && %n ) 
      { say "3. @n && %n"           } # $_ ~~ @n && $_ ~~ %n ???

Processing []...

Processing [0]...
1. In %n
2. In @n

Processing [1]...

Processing [Barney]...
1. In %n
2. In @n


macbookpro_brian[2845]$ perl5.10.0 -V
Summary of my perl5 (revision 5 version 10 subversion 0) configuration:
    osname=darwin, osvers=8.10.1, archname=darwin-2level
    uname='darwin 8.10.1 darwin kernel
version 8.10.1: wed may 23 16:33:00 pdt 2007;
root:xnu-792.22.5~1release_i386 i386 i386 '
    hint=recommended, useposix=true, d_sigaction=define
    useithreads=undef, usemultiplicity=undef
    useperlio=define, d_sfio=undef, uselargefiles=define, usesocks=undef
    use64bitint=undef, use64bitall=undef, uselongdouble=undef
    usemymalloc=n, bincompat5005=undef
    cc='cc', ccflags ='-fno-common -DPERL_DARWIN -no-cpp-precomp
-fno-strict-aliasing -pipe -I/usr/local/include -I/opt/local/include',
    cppflags='-no-cpp-precomp -fno-common -DPERL_DARWIN -no-cpp-precomp
-fno-strict-aliasing -pipe -I/usr/local/include -I/opt/local/include'
    ccversion='', gccversion='4.0.1 (Apple Computer, Inc. build 5363)',
    intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234
    d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16
    ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='off_t',
    alignbytes=8, prototype=define
  Linker and Libraries:
    ld='env MACOSX_DEPLOYMENT_TARGET=10.3 cc', ldflags ='
-L/usr/local/lib -L/opt/local/lib'
    libpth=/usr/local/lib /opt/local/lib /usr/lib
    libs=-ldbm -ldl -lm -lc
    perllibs=-ldl -lm -lc
    libc=/usr/lib/libc.dylib, so=dylib, useshrplib=false,
  Dynamic Linking:
    dlsrc=dl_dlopen.xs, dlext=bundle, d_dlsymun=undef, ccdlflags=' '
    cccdlflags=' ', lddlflags=' -bundle -undefined dynamic_lookup
-L/usr/local/lib -L/opt/local/lib'

Characteristics of this binary (from libperl): 
                        USE_LARGE_FILES USE_PERLIO
  Locally applied patches:
  Built under darwin
  Compiled at Dec  2 2007 12:18:58

Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About