Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister

Strange Smart Match behavior

by OverlordQ (Hermit)
on May 26, 2011 at 19:31 UTC ( [id://906887] : perlquestion . print w/replies, xml ) Need Help??

OverlordQ has asked for the wisdom of the Perl Monks concerning the following question:

What my intended purpose is to take the return value of a function call that gets the status of our object and compares it to an array of 'valid' statuses. psudo code for this is effectively:
my $obj = ObjectStuff->load(objid); my $status = $obj->getStatus(); my @validStatus = split(',', $csv_of_active_status); unless ( $status ~~ @validStatus ) { #spew warnings; exit; }
Now the issue came up that our error checking on the load call isn't optimal, so we didn't throw an error when we should. My train of thought then went too, well if we created an invalid object, we cant get the status of it and so the smart match will fail. However it doesnt.

From what I can tell the string is defined, but empty, with some weird properties.

My minimal test case is as follows:
#!/usr/bin/perl use Object::Module; use Data::Dumper; my $obj = Object::Module::load({id => 'OMGWTFBBQ'}); die unless $obj; my @goodStatus = ... my $mystery = $obj->get_status(); use Devel::Peek; print "mystery Dump\n--------\n"; print Dumper($mystery); print "\nmystery Peek\n--------\n"; Dump($mystery); my $empty = ''; print "\nEmpty Dump\n--------\n"; print Dumper($empty); print "\nEmpty Peek\n--------\n"; Dump($empty); if ( defined $mystery ) { print "mystery defined\n"; } if ( defined $empty ) { print "Empty defined\n"; } print "\nArray Dump\n--------\n"; print Dumper(@goodStatus); if( ($mystery) ~~ @goodStatus ) { print "Status is valid!\n"; } if( ($empty) ~~ @goodStatus ) { print "Empty is valid!\n"; }
Running this you recieve the following output:
mystery Dump -------- $VAR1 = ''; mystery Peek -------- SV = PVNV(0xa5317e4) at 0x982ec48 REFCNT = 1 FLAGS = (PADMY,IOK,NOK,POK,pIOK,pNOK,pPOK) IV = 0 NV = 0 PV = 0x9b36a68 ""\0 CUR = 0 LEN = 4 Empty Dump -------- $VAR1 = ''; Empty Peek -------- SV = PV(0xa50ea88) at 0x9d6e6f0 REFCNT = 1 FLAGS = (PADMY,POK,pPOK) PV = 0xa48f740 ""\0 CUR = 0 LEN = 4 mystery defined Empty defined Array Dump -------- $VAR1 = '128'; $VAR2 = '1'; $VAR3 = '0'; $VAR4 = '-3'; Status is valid!
First thing to note is from Dumper, they look the same. Devel::Peek gives a bit different picture though.

Now the weirdness (imo) comes in during the smart match, despite them appearing to be the exact same thing, the mystery value matches successfully while the empty string doesn't.

EDIT: But it doesn't stop there. Let's add an equality check. If we throw in:
if ( $mystery eq $empty ) { print "ASCII Equal!\n"; } in there, we get
... Empty defined ASCII Equal! Array Dump -------- $VAR1 = '128'; $VAR2 = '1'; $VAR3 = '0'; $VAR4 = '-3'; Status is valid!
So they're equal . . interesting. How about numerically?
if ( $mystery == $empty ) { print "Number Equal!\n"; }
And we get:
ASCII Equal! Number Equal! Array Dump -------- $VAR1 = '128'; $VAR2 = '1'; $VAR3 = '0'; $VAR4 = '-3'; Status is valid! Empty is valid!
Wait, now Empty is valid too?

Edit2: And in case anybody asks:
$ perl -v This is perl, v5.10.0 built for i486-linux-gnu-thread-multi
And our Object module is based on Class::Std. Now the reproducibility of this might be impossible as I can't give up the module or the database, but I'd be more then willing to run code/modules/etc to diagnose.

Replies are listed 'Best First'.
Re: Strange Smart Match behavior
by moritz (Cardinal) on May 26, 2011 at 21:20 UTC

    I haven't looked at your problem in detail, but I can tell you that the behavior of smart matching changed a lot between 5.10.0 and 5.10.1 (whereas it's relatively stable since 5.10.1).

    Relying on the smart matching features of 5.10.0 thus isn't the best of ideas, comparable to building your house on sand.

    A quick glance over the debug output implies that $mistery is the empty string, and thus numerically compares equal to '0'. But I could be wrong here.

      But then why would setting a variable to the explicity empty string fail to match, unless it was first compared to $mystery