String comparison operator trouble

Discussion in 'Perl Misc' started by J.D. Baldwin, Jul 16, 2008.

  1. J.D. Baldwin

    J.D. Baldwin Guest

    I solved my problem by rewriting, but I'm wondering why I am getting errors
    with respect to 'ne' and 'eq' operators.

    This code works fine (Perl 5.8.8):

    $ cat minimal.pl
    #!/opt/gnu/bin/perl

    use warnings;
    use strict;

    my $VAL = 'xyz';

    my @foo = ( 'abc', 'def', 'ghi', 'xyz', 'jkl', 'xyz', 'uvw' );

    foreach my $item ( @foo )
    {
    next if ( $item ne $VAL );

    print "$item\n";
    }
    $ ./minimal.pl
    xyz
    xyz


    But if I add a test for 'undef' I get warnings:

    $ cat ./minimal2.pl
    #!/opt/gnu/bin/perl

    use warnings;
    use strict;

    my $VAL = 'xyz';

    my @foo = ( 'abc', 'def', 'ghi', 'xyz', 'jkl', 'xyz', 'uvw' );

    foreach my $item ( @foo )
    {
    next if ( undef $item ) or ( $item ne $VAL );

    print "$item\n";
    }
    $ ./minimal2.pl
    Use of uninitialized value in string ne at ./minimal2.pl line 12.
    Use of uninitialized value in string ne at ./minimal2.pl line 12.
    Use of uninitialized value in string ne at ./minimal2.pl line 12.
    Use of uninitialized value in string ne at ./minimal2.pl line 12.
    Use of uninitialized value in string ne at ./minimal2.pl line 12.
    Use of uninitialized value in string ne at ./minimal2.pl line 12.
    Use of uninitialized value in string ne at ./minimal2.pl line 12.

    Even weirder if I try 'eq':

    $ cat ./minimal3.pl
    #!/opt/gnu/bin/perl

    use warnings;
    use strict;

    my $VAL = 'xyz';

    my @foo = ( 'abc', 'def', 'ghi', 'xyz', 'jkl', 'xyz', 'uvw' );

    foreach my $item ( @foo )
    {
    next if ( undef $item ) or ( $item eq $VAL );

    print "$item\n";
    }
    $ ./minimal3.pl
    Use of uninitialized value in string eq at ./minimal3.pl line 12.
    Use of uninitialized value in concatenation (.) or string at ./minimal3.pl line 14.

    Use of uninitialized value in string eq at ./minimal3.pl line 12.
    Use of uninitialized value in concatenation (.) or string at ./minimal3.pl line 14.

    Use of uninitialized value in string eq at ./minimal3.pl line 12.
    Use of uninitialized value in concatenation (.) or string at ./minimal3.pl line 14.

    Use of uninitialized value in string eq at ./minimal3.pl line 12.
    Use of uninitialized value in concatenation (.) or string at ./minimal3.pl line 14.

    Use of uninitialized value in string eq at ./minimal3.pl line 12.
    Use of uninitialized value in concatenation (.) or string at ./minimal3.pl line 14.

    Use of uninitialized value in string eq at ./minimal3.pl line 12.
    Use of uninitialized value in concatenation (.) or string at ./minimal3.pl line 14.

    Use of uninitialized value in string eq at ./minimal3.pl line 12.
    Use of uninitialized value in concatenation (.) or string at ./minimal3.pl line 14.

    Can anyone explain to me why I see this behavior? It seems like a
    perfectly normal chained test.
    --
    _+_ From the catapult of |If anyone disagrees with any statement I make, I
    _|70|___:)=}- J.D. Baldwin |am quite prepared not only to retract it, but also
    \ / |to deny under oath that I ever made it. -T. Lehrer
    ***~~~~-----------------------------------------------------------------------
     
    J.D. Baldwin, Jul 16, 2008
    #1
    1. Advertising

  2. J.D. Baldwin <> wrote:
    > I solved my problem by rewriting, but I'm wondering why I am getting errors
    > with respect to 'ne' and 'eq' operators.


    > This code works fine (Perl 5.8.8):


    > $ cat minimal.pl
    > #!/opt/gnu/bin/perl
    >
    > use warnings;
    > use strict;
    >
    > my $VAL = 'xyz';
    >
    > my @foo = ( 'abc', 'def', 'ghi', 'xyz', 'jkl', 'xyz', 'uvw' );
    >
    > foreach my $item ( @foo )
    > {
    > next if ( $item ne $VAL );
    >
    > print "$item\n";
    > }
    > $ ./minimal.pl
    > xyz
    > xyz



    > But if I add a test for 'undef' I get warnings:


    > $ cat ./minimal2.pl
    > #!/opt/gnu/bin/perl
    >
    > use warnings;
    > use strict;
    >
    > my $VAL = 'xyz';
    >
    > my @foo = ( 'abc', 'def', 'ghi', 'xyz', 'jkl', 'xyz', 'uvw' );
    >
    > foreach my $item ( @foo )
    > {
    > next if ( undef $item ) or ( $item ne $VAL );


    'undef' is an unary operator that undefines what it's applied to,
    not a test if the variable is undefined. I guess you meant to use

    next if ! defined $item || $item ne $VAL;
    or
    next unless defined $item && $item eq $val;

    Regards, Jens
    --
    \ Jens Thoms Toerring ___
    \__________________________ http://toerring.de
     
    Jens Thoms Toerring, Jul 16, 2008
    #2
    1. Advertising

  3. J.D. Baldwin

    szr Guest

    J.D. Baldwin wrote:
    > I solved my problem by rewriting, but I'm wondering why I am getting
    > errors
    > with respect to 'ne' and 'eq' operators.


    [...]

    > But if I add a test for 'undef' I get warnings:
    >
    > $ cat ./minimal2.pl
    > #!/opt/gnu/bin/perl
    >
    > use warnings;
    > use strict;
    >
    > my $VAL = 'xyz';
    >
    > my @foo = ( 'abc', 'def', 'ghi', 'xyz', 'jkl', 'xyz', 'uvw' );
    >
    > foreach my $item ( @foo )
    > {
    > next if ( undef $item ) or ( $item ne $VAL );
    >
    > print "$item\n";
    > }
    > $ ./minimal2.pl
    > Use of uninitialized value in string ne at ./minimal2.pl line 12.
    > Use of uninitialized value in string ne at ./minimal2.pl line 12.
    > Use of uninitialized value in string ne at ./minimal2.pl line 12.
    > Use of uninitialized value in string ne at ./minimal2.pl line 12.
    > Use of uninitialized value in string ne at ./minimal2.pl line 12.
    > Use of uninitialized value in string ne at ./minimal2.pl line 12.
    > Use of uninitialized value in string ne at ./minimal2.pl line 12.


    The problem is you're calling undef $item which undefines $item.

    What you want to use instead is:

    next if ( ! defined $item ) or ( $item ne $VAL );


    defined() will tell you if a scalar has been defined or so. For arrays
    and hashes, drop the define, as if(@array) and if(%hash) will return
    true only if there are items within.

    Also see: perldoc -f defined and also: perldoc -f undef
    This will help you learn what undef() is used for and about using
    defined().

    How this helps.

    --
    szr
     
    szr, Jul 16, 2008
    #3
  4. J.D. Baldwin

    Dave B Guest

    J.D. Baldwin wrote:

    > next if ( undef $item )


    $item == undef

    or

    !defined($item)

    "perldoc -f undef" to see why your command does not do what you want, and
    the warnings you get are expected.

    --
    D.
     
    Dave B, Jul 16, 2008
    #4
  5. J.D. Baldwin

    Jim Gibson Guest

    In article <g5l4ig$c54$>, J.D. Baldwin
    <> wrote:

    > I solved my problem by rewriting, but I'm wondering why I am getting errors
    > with respect to 'ne' and 'eq' operators.
    >


    > But if I add a test for 'undef' I get warnings:
    >
    > $ cat ./minimal2.pl
    > #!/opt/gnu/bin/perl
    >
    > use warnings;
    > use strict;
    >
    > my $VAL = 'xyz';
    >
    > my @foo = ( 'abc', 'def', 'ghi', 'xyz', 'jkl', 'xyz', 'uvw' );
    >
    > foreach my $item ( @foo )
    > {
    > next if ( undef $item ) or ( $item ne $VAL );
    >
    > print "$item\n";
    > }


    The test for defined-ness is defined, not undef. The operator undef
    sets the variable to undef.

    perldoc -f defined

    --
    Jim Gibson
     
    Jim Gibson, Jul 16, 2008
    #5
  6. Dave B wrote:
    > J.D. Baldwin wrote:
    >
    >> next if ( undef $item )

    >
    > $item == undef


    That won't work correctly either.

    $ perl -le'
    for my $item ( 0, 1, "two" ) {
    print $item if $item == undef;
    }
    '
    0
    two


    John
    --
    Perl isn't a toolbox, but a small machine shop where you
    can special-order certain sorts of tools at low cost and
    in short order. -- Larry Wall
     
    John W. Krahn, Jul 16, 2008
    #6
  7. J.D. Baldwin

    Uri Guttman Guest

    >>>>> "DB" == Dave B <> writes:

    DB> J.D. Baldwin wrote:
    >> next if ( undef $item )


    DB> $item == undef

    very wrong. the only way to test for definedness is with defined. wipe
    that idiom out of your brain. just to make it clear, try that with any
    false value in $item (and enable warnings too for more results).

    uri

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Free Perl Training --- http://perlhunter.com/college.html ---------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
     
    Uri Guttman, Jul 16, 2008
    #7
  8. Dave B <> wrote:
    >J.D. Baldwin wrote:
    >
    >> next if ( undef $item )

    >
    >$item == undef


    This doesn't do what you seem to think it is doing.

    First of all it will trigger two warnings (for generic $item):
    - Use of uninitialized value in numeric eq (==) [*]
    - Argument "...." isn't numeric in numeric eq (==) [**]

    [*]: because undef is not initialized, surprise, surprise
    [**]: because in the generic case $item may contain a string or -gasp-
    be undefined instead of number.

    And second the numerical value of undef is 0 and therefore this
    comparison will yield true whenever the numerical value of $item is 0,
    in particular also when $item contains a string that does not start with
    a number.

    jue
     
    Jürgen Exner, Jul 16, 2008
    #8
  9. J.D. Baldwin

    J.D. Baldwin Guest

    In the previous article, Jens Thoms Toerring <> wrote:
    > 'undef' is an unary operator that undefines what it's applied to,
    > not a test if the variable is undefined. I guess you meant to use


    <slaps forehead>

    So much for focusing on the comparison operator.

    Thank you (and you others) for setting me straight on this.

    undef ne ( ! defined ). Got it.
    --
    _+_ From the catapult of |If anyone disagrees with any statement I make, I
    _|70|___:)=}- J.D. Baldwin |am quite prepared not only to retract it, but also
    \ / |to deny under oath that I ever made it. -T. Lehrer
    ***~~~~-----------------------------------------------------------------------
     
    J.D. Baldwin, Jul 16, 2008
    #9
  10. J.D. Baldwin

    Dave B Guest

    Jürgen Exner wrote:

    > Dave B <> wrote:
    >> J.D. Baldwin wrote:
    >>
    >>> next if ( undef $item )

    >> $item == undef

    >
    > This doesn't do what you seem to think it is doing.


    Thank you, John and Uri for correcting me on this. It seemed to work in a
    quick and simple test like perl -e 'print "ok" if $var == undef;' but, as
    you correctly point out, that idiom cannot be used in general.

    Thanks

    --
    D.
     
    Dave B, Jul 16, 2008
    #10
  11. J.D. Baldwin

    Uri Guttman Guest

    >>>>> "DB" == Dave B <> writes:

    DB> Jürgen Exner wrote:
    >> Dave B <> wrote:
    >>> J.D. Baldwin wrote:
    >>>
    >>>> next if ( undef $item )
    >>> $item == undef

    >>
    >> This doesn't do what you seem to think it is doing.


    DB> Thank you, John and Uri for correcting me on this. It seemed to work in a
    DB> quick and simple test like perl -e 'print "ok" if $var == undef;' but, as
    DB> you correctly point out, that idiom cannot be used in general.

    in general or at all. it fails for too many scalar values (as someone
    else said, any string that starts with a non-digit will fail among
    others). so don't call it an idiom, it is a bug.

    uri

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Free Perl Training --- http://perlhunter.com/college.html ---------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
     
    Uri Guttman, Jul 16, 2008
    #11
  12. J.D. Baldwin

    szr Guest

    Jürgen Exner wrote:
    > Dave B <> wrote:
    >> J.D. Baldwin wrote:
    >>
    >>> next if ( undef $item )

    >>
    >> $item == undef

    >
    > This doesn't do what you seem to think it is doing.


    Indeed, == forces a numeric context, so undef becomes 0. using 'eq'
    interestingly seems to work (though, still with warnings - see below.)

    > First of all it will trigger two warnings (for generic $item):
    > - Use of uninitialized value in numeric eq (==) [*]
    > - Argument "...." isn't numeric in numeric eq (==) [**]
    >
    >
    > [*]: because undef is not initialized, surprise, surprise
    > [**]: because in the generic case $item may contain a string or -gasp-
    > be undefined instead of number.


    I get a different set of warnings (using both 5.10.0 and 5.8.8)

    $ perl5.8.8 -Mstrict -Mwarnings -we 'my $x = 1; print +($x == undef ?
    "[undef]" : "[$x]"), "\n";'
    Warning: Use of "undef" without parentheses is ambiguous at -e line 1.
    Search pattern not terminated or ternary operator parsed as search
    pattern at -e line 1.

    I'm not sure where it's getting "Search pattern from, but I'm guessing
    this has something to do with using (if ? then : else) instead of
    if{}else{} ?


    $ perl5.8.8 -Mstrict -Mwarnings -we 'my $x = 1; print +($x eq (undef)
    ? "[undef]" : "[$x]"), "\n";'
    Use of uninitialized value in string eq at -e line 1.
    [1]

    $ perl5.8.8 -Mstrict -Mwarnings -we 'my $x = 0; print +($x eq (undef)
    ? "[undef]" : "[$x]"), "\n";'
    Use of uninitialized value in string eq at -e line 1.
    [0]

    $ -Mstrict -Mwarnings -we 'my $x = undef; print +($x eq (undef) ?
    "[undef]" : "[$x]"), "\n";'
    Use of uninitialized value in string eq at -e line 1.
    Use of uninitialized value in string eq at -e line 1.
    [undef]

    Of course, I wouldn't use this in any real code, and one should always
    use defined($scalar) to test for defininty.

    --
    szr
     
    szr, Jul 16, 2008
    #12
  13. J.D. Baldwin

    Uri Guttman Guest

    >>>>> "s" == szr <> writes:

    s> Jürgen Exner wrote:
    >> Dave B <> wrote:
    >>> J.D. Baldwin wrote:
    >>>
    >>>> next if ( undef $item )
    >>>
    >>> $item == undef

    >>
    >> This doesn't do what you seem to think it is doing.


    s> Indeed, == forces a numeric context, so undef becomes 0. using 'eq'
    s> interestingly seems to work (though, still with warnings - see below.)

    what do you mean seems to work? try '' eq undef. the rule is simple,
    don't use undef in any comparisons. that is why defined is NEEDED. it is
    the only way to test for undef (which is out of band data for all other
    ops).

    s> Of course, I wouldn't use this in any real code, and one should always
    s> use defined($scalar) to test for defininty.

    then don't say things like it seems to work for eq when you know it
    doesn't.

    uri

    --
    Uri Guttman ------ -------- http://www.sysarch.com --
    ----- Perl Code Review , Architecture, Development, Training, Support ------
    --------- Free Perl Training --- http://perlhunter.com/college.html ---------
    --------- Gourmet Hot Cocoa Mix ---- http://bestfriendscocoa.com ---------
     
    Uri Guttman, Jul 16, 2008
    #13
  14. J.D. Baldwin

    szr Guest

    Uri Guttman wrote:
    >>>>>> "s" == szr <> writes:

    >
    > > Jürgen Exner wrote:
    > >> Dave B <> wrote:
    > >>> J.D. Baldwin wrote:
    > >>>
    > >>>> next if ( undef $item )
    > >>>
    > >>> $item == undef
    > >>
    > >> This doesn't do what you seem to think it is doing.

    >
    > s> Indeed, == forces a numeric context, so undef becomes 0. using
    > s> 'eq' interestingly seems to work (though, still with warnings -
    > s> see below.)
    >
    > what do you mean seems to work? try '' eq undef. the rule is simple,
    > don't use undef in any comparisons. that is why defined is NEEDED. it
    > is the only way to test for undef (which is out of band data for all
    > other ops).
    >
    > s> Of course, I wouldn't use this in any real code, and one should
    > always s> use defined($scalar) to test for defininty.
    >
    > then don't say things like it seems to work for eq when you know it
    > doesn't.


    No need to get upset. "Seems to work" only referred to having to
    appearance to work as expected within the limit of those test cases. I
    never said it's something that should be used, and in fact, I pointed to
    the exact opposite, to not use such a construct and instead use
    defined($scalar)

    --
    szr
     
    szr, Jul 16, 2008
    #14
  15. J.D. Baldwin

    Hans Mulder Guest

    szr wrote:
    > Jürgen Exner wrote:
    >> Dave B <> wrote:


    >>> $item == undef


    > I get a different set of warnings (using both 5.10.0 and 5.8.8)
    >
    > $ perl5.8.8 -Mstrict -Mwarnings -we 'my $x = 1; print +($x == undef ?
    > "[undef]" : "[$x]"), "\n";'
    > Warning: Use of "undef" without parentheses is ambiguous at -e line 1.
    > Search pattern not terminated or ternary operator parsed as search
    > pattern at -e line 1.
    >
    > I'm not sure where it's getting "Search pattern from, but I'm guessing
    > this has something to do with using (if ? then : else) instead of
    > if{}else{} ?


    The "undef" operator takes an argument if it can find one.
    If the first non-whitespace character after "undef" is a "?",
    then the parser assumes this is a ??-style pattern match.

    In this case, there is no closing "?". If there were one, then
    you'd get a message that "undef" wants an lvalue argument and
    pattern matches are not lvalues.

    As the other warning points out, you can avoid this kind of mis-
    parse by writing "undef()".

    In theory you can leave out the parentheses if the next character
    is a one that cannot be the first in an expression (such as ";").
    This only works if you know about obscure kinds of expressions
    (such as *globs and ??-patterns).

    For example, you might think that "undef * 5" looks like multiplication,
    but perl interprets this as undef(*5). As it happens, *5 is an lvalue,
    so this will "work" (for some definition of "work").

    Don't try this at home, kids.

    -- HansM
     
    Hans Mulder, Jul 17, 2008
    #15
  16. J.D. Baldwin

    szr Guest

    Hans Mulder wrote:
    > szr wrote:
    >> Jürgen Exner wrote:
    >>> Dave B <> wrote:

    >
    >>>> $item == undef

    >
    >> I get a different set of warnings (using both 5.10.0 and 5.8.8)
    >>
    >> $ perl5.8.8 -Mstrict -Mwarnings -we 'my $x = 1; print +($x ==
    >> undef ? "[undef]" : "[$x]"), "\n";'
    >> Warning: Use of "undef" without parentheses is ambiguous at -e
    >> line 1. Search pattern not terminated or ternary operator parsed
    >> as search pattern at -e line 1.
    >>
    >> I'm not sure where it's getting "Search pattern from, but I'm
    >> guessing this has something to do with using (if ? then : else)
    >> instead of if{}else{} ?

    >
    > The "undef" operator takes an argument if it can find one.
    > If the first non-whitespace character after "undef" is a "?",
    > then the parser assumes this is a ??-style pattern match.
    >
    > In this case, there is no closing "?". If there were one, then
    > you'd get a message that "undef" wants an lvalue argument and
    > pattern matches are not lvalues.


    Ah I didn't realize that, thank you.

    > As the other warning points out, you can avoid this kind of mis-
    > parse by writing "undef()".
    >
    > In theory you can leave out the parentheses if the next character
    > is a one that cannot be the first in an expression (such as ";").
    > This only works if you know about obscure kinds of expressions
    > (such as *globs and ??-patterns).


    Seems being explicit is once again the safer way.

    > For example, you might think that "undef * 5" looks like
    > multiplication, but perl interprets this as undef(*5). As it
    > happens, *5 is an lvalue, so this will "work" (for some definition of
    > "work").


    This is true. Many people seem to be confused as to just how to use
    undef(), as some see it as a (none) value to be assigned to return a
    scalar to an undefined state, rather than as a function and knowing
    exactly what it does.


    Thank you for taking the time to reply.

    --
    szr
     
    szr, Jul 18, 2008
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. jstanforth
    Replies:
    13
    Views:
    12,870
  2. Will McGugan

    case insensitive comparison operator ?

    Will McGugan, Aug 18, 2004, in forum: Python
    Replies:
    2
    Views:
    8,883
    Max M
    Aug 18, 2004
  3. Replies:
    21
    Views:
    1,443
    Alex Vinokur
    Aug 18, 2007
  4. Smithers
    Replies:
    12
    Views:
    1,202
    Ben Voigt [C++ MVP]
    Jul 7, 2009
  5. Deepu
    Replies:
    1
    Views:
    261
    ccc31807
    Feb 7, 2011
Loading...

Share This Page