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

Perl has "convenient" behaviors which optimize away common cases for folks. Some of those deal with how undefined values are handled:

#!/usr/bin/perl -l use strict; my $x; print +($x eq '') ? 'Yes' : 'No';

That prints "yes", even though an undefined value is not the same as the empty string. Many times this is what you want, but not always. To get around this, the following verbose code will suffice:

#!/usr/bin/perl -l use strict; my $x; print +(defined $x && $x eq '') ? 'Yes' : 'No';

It gets much worse if you're comparing two variables:

if ( (not defined $new and not defined $old) or (defined $new and defined $old and $old eq $new) ) { ... }

Is there some way to get Perl to force a true comparison? (yes, I can wrap that in a sub or method, but I'd like a direct comparison)

Update: the following comparison is probably a bit faster but I doubt it's easier to read.

!( defined $x xor defined $y ) && $x eq $y

Cheers,
Ovid

New address of my CGI Course.

Replies are listed 'Best First'.
Re: Comparing undefined values
by GrandFather (Saint) on Dec 16, 2005 at 20:39 UTC

    !( defined $x xor defined $y ) could be rewritten as defined $x == defined $y which is shorter and clearer. xor and != are equivelent for boolean values.


    DWIM is Perl's answer to Gödel
Re: Comparing undefined values
by xdg (Monsignor) on Dec 16, 2005 at 20:32 UTC

    How about this:

    ( defined($p) ? '1' . $p : 0 ) eq ( defined($q) ? '1' . $q : 0 )

    For example:

    use strict; use warnings; my %strings = ( 'undef' => undef, 'empty' => '', 'string' => '0' ); my @pairs = ( [ 'undef' , 'undef' ], [ 'undef' , 'empty' ], [ 'undef' , 'string' ], [ 'empty' , 'empty' ], [ 'empty' , 'string' ], [ 'string', 'string' ], ); for ( @pairs ) { my ($p,$q) = @strings{@$_}; my $cmp = ( (defined($p) ? '1' . $p : 0) eq (defined($q) ? '1' . $q : 0) ) ? 'true' : 'false'; print join(" eq ", @$_), " = $cmp\n"; }

    Result:

    undef eq undef = true undef eq empty = false undef eq string = false empty eq empty = true empty eq string = false string eq string = true

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

      Great mind, great minds ... ;)

      Here's the test program I wrote:

      #!/usr/bin/perl -l use strict; use warnings; use Math::Combinatorics; my %v = ( undef => undef, empty => '', zero => 0, name => 'Ovid', ); my $combine = Math::Combinatorics->new( count => 2, data => [ keys %v ], ); while ( my ( $x, $y ) = $combine->next_combination ) { compare( $x, $y ); } foreach my $x ( keys %v ) { compare( $x, $x ); } sub compare { my ( $x, $y ) = @_; my ($X, $Y) = ($v{$x}, $v{$y}); print "\nComparing '$x' and '$y'"; no warnings 'uninitialized'; print +( ( defined $X == defined $Y ) && $X eq $Y ) ? "yes" : "no"; }

      Cheers,
      Ovid

      New address of my CGI Course.

Re: Comparing undefined values
by japhy (Canon) on Dec 16, 2005 at 19:46 UTC
    You mean something akin to the "identity equality" operators that I think Python, Ruby, and JavaScript have?
    if ($x === $y) { ... } if ($a !== $b) { ... }
    No, as far as I know, there's nothing for that right now, although Perl 6 probably has it.

    Jeff japhy Pinyan, P.L., P.M., P.O.D, X.S.: Perl, regex, and perl hacker
    How can we ever be the sold short or the cheated, we who for every service have long ago been overpaid? ~~ Meister Eckhart

      Yup, I think that would be it. Though right now I'd probably call it the "no, damn it, I really do mean equal" operator. Perhaps it would be uncommon enough that we wouldn't need to Huffman encode the name.

      Cheers,
      Ovid

      New address of my CGI Course.

Re: Comparing undefined values
by ikegami (Patriarch) on Dec 16, 2005 at 20:52 UTC
    Smart match might be of interest. Looks like '' ~~ $x does exactly what you want. Dunno about $x ~~ ''.

    Update: $x ~~ '' works as well, according to the patch's author. They don't even warn.

Re: Comparing undefined values
by ikegami (Patriarch) on Dec 16, 2005 at 20:05 UTC
    I don't think it's an optimization. eq requires strings, so its operands get stringified. What would you have be the string value of undef? I think it's pretty natural to stringify undef to the nul string (with a warning).
      This opens up the whole line of strong typing, comparing/combining like types, casting to like types, and autoconversion of unlike types.

      I've always found it difficult in other languages to determine which type wins in the comparison wars. Where there is more than one kind of numeric type, I have to keep a cheat sheet.

      -QM
      --
      Quantum Mechanics: The dreams stuff is made of