I posted this to perl5porters without response, and
also filed a bug report without a response. I figure it's
either a bug no one has time to think about or I'm just an idiot (and
I figure it might be a coin flip between those two). 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()
:
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 argument.
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 ??? } __DATA__ Processing []... Processing [0]... 1. In %n 2. In @n Processing [1]... Processing [Barney]... 1. In %n 2. In @n
Here's my machine and perl info:
macbookpro_brian[2845]$ perl5.10.0 -V Summary of my perl5 (revision 5 version 10 subversion 0) configuration: Platform: osname=darwin, osvers=8.10.1, archname=darwin-2level uname='darwin alexandria2-10.nyc.access.net 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 ' config_args='' 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 Compiler: cc='cc', ccflags ='-fno-common -DPERL_DARWIN -no-cpp-precomp -fno-strict-aliasing -pipe -I/usr/local/include -I/opt/local/include', optimize='-O3', 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)', gccosandvers='' 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', lseeksize=8 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, libperl=libperl.a gnulibc_version='' 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): Compile-time options: PERL_DONT_CREATE_GVSV PERL_MALLOC_WRAP USE_LARGE_FILES USE_PERLIO Locally applied patches: RC2 Built under darwin Compiled at Dec 2 2007 12:18:58 @INC: /usr/local/perls/perl-5.10.0-rc2/lib/5.10.0/darwin-2level /usr/local/perls/perl-5.10.0-rc2/lib/5.10.0 /usr/local/perls/perl-5.10.0-rc2/lib/site_perl/5.10.0/darwin-2level /usr/local/perls/perl-5.10.0-rc2/lib/site_perl/5.10.0 .
( scalar( @n ) and scalar( %n ) )
~~ 'Barney'
Re:It's broken
jjore on 2008-02-18T08:25:42
That is:( 3 and '2/8' ) ~~ 'Barney'
I know the quality of answers can vary quite a bit, but Perlmonks still can be a good resource for answers.