Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

How come undef eq '' ??

by tmharish (Friar)
on Jan 30, 2013 at 15:23 UTC ( [id://1016083]=perlquestion: print w/replies, xml ) Need Help??

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

I, accidentally stumbled on the fact that undef eq ''

( Leaving out strict and warnings is intentional )

perl -e 'if( undef eq "" ) { print "In\n" } else { print "Out\n" }' In perl -e 'my $tmp; if( $tmp eq "" ) { print "In\n" } else { print "Out\ +n" }' In perl -e 'my $tmp; if( $tmp ne "" ) { print "In\n" } else { print "Out\ +n" }' Out perl -e 'if( undef ne "" ) { print "In\n" } else { print "Out\n" }' Out

Is there some reasoning for this?

The problem with this is that when I want to clean up warnings I add $tmp and:

perl -e 'my $tmp; if( $tmp and ( $tmp eq "" ) ) { print "In\n" } else +{ print "Out\n" }' Out

The outcome is to throw the entire program off!

Replies are listed 'Best First'.
Re: How come undef eq '' ??
by LanX (Saint) on Jan 30, 2013 at 15:49 UTC
    For good reasons operators in Perl do type conversions!

  • ==, + - * and so on do numification so undef is considered 0

  • eq, . and so on do stringification so undef is considered empty string "".

    Anyway using warnings you'll often get "Use of uninitialized value" messages.

    I do not understand what your intentions are, but if you wanna test for undef use the designated functions defined or //

    EDIT

    Equality Operators in perlop

           Binary "==" returns true if the left argument is numerically equal to
           the right argument.
    ...
           Binary "eq" returns true if the left argument is stringwise equal to
           the right argument.
    

    Cheers Rolf

Re: How come undef eq '' ??
by muba (Priest) on Jan 30, 2013 at 15:52 UTC

    Because perl does a lot of automatic data type coercion for you if it's needed.

    If undef didn't stringify to "", then what output should this produce?

    print "a" . undef . "b";

    With undef stringifying to "", this neatly prints "ab". If undef would stringify to, say, "undef", like how Javascript's null stringifies to "null", the above code would output "aundefb", which hardly seems desireable.

    If you need to test for definedness of a value, then you have your defined function, or your defined-or // operator.

    In your last code snipped,

    perl -e 'my $tmp; if( $tmp and ( $tmp eq "" ) ) { print "In\n" } else +{ print "Out\n" }' Out
    what output did you expect? Why?

    The reason you're getting "Out" here is not because of how undef stringifies, it's because of undef being considered false. So in the expression $tmp and ( $tmp eq "" ), the and operator looks at its left-hand side, concludes that it's false, and so returns false, causing your if-else to jump to the else part right away. Whether or not ($tmp eq "") is never evaluated in that snippet.


    Addendum: the raison d'être of undef is that it can convey the meaning of "there is no valid value for what you asked for," for example if you have a function that returns the next paragraph from some document, then "" would mean that the next paragraph is empty, and undef would mean that there is no next paragraph.

Re: How come undef eq '' ??
by eyepopslikeamosquito (Archbishop) on Jan 30, 2013 at 17:07 UTC

      Guess the essence is:

      Unless you really know how Perl works ... use strict; use warnings;

      Thanks for the link

        I thought 'use warnings' was discouraged for published modules? I've always added it for development, but removed for distribution.
Re: How come undef eq '' ?? (coersion, numification, truth)
by Anonymous Monk on Jan 30, 2013 at 15:27 UTC
Re: How come undef eq '' ??
by tmharish (Friar) on Jan 30, 2013 at 15:45 UTC

    Not to get into a discussion on what perl should do but:

    perl -e 'if( $tmp eq 0 ) { print "In\n" } else { print "Out\n" }' Out

    By the same logic - I cant seem to understand why this is not true! Especially considering undef $a; $a++ works as expected.

      Because eq is for string comparisons. undef stringifies to "", 0 stringifies to "0", and "" ne "0".

      Change eq to == and it will print "In".

      eq is for string comparison. ++ is a numeric operator. Maybe that's where the root of the preceived discrepancy lies?

      Corion, muba ... Yup, with the 0 I should have used == and it would have been consistent with eq and ''.

      Thanks!

Re: How come undef eq '' ??
by tmharish (Friar) on Jan 30, 2013 at 17:04 UTC

    LanX, muba

    My intentions were essentially to clean up a previously un-maintained module on CPAN

    The original author had worked with no warnings; and I was trying to enable warings.

    To get out of the Use of uninitialized value I started adding the $blah AND $blah ... ... which is when I got totally caught up in this.

    Complete code on GitHup ( line 1025 ) ...

    Is there a more graceful way of doing this other than disabling warnings for that chunk - through __WARN__ - as I have done there? ( without having to think through each conditional statement! )

      Is there a more graceful way of doing this other than disabling warnings for that chunk - through __WARN__ - as I have done there?
      I think your introduction of _unset_sig_warn() was misguided. Why not simply use lexical warnings? (see: perllexwarn). You typically switch off specific warnings in the smallest possible lexical scope. For example:
      use strict; use warnings; my $z; # $z contains undef if ($z eq "") { # oops, Use of uninitialized value $z in string eq print "1. string is empty (with warnings)\n"; } # Switch off the specific uninitialized warning in a lexical scope. { no warnings 'uninitialized'; if ($z eq "") { # no warning this time print "2. string is empty (with no warnings)\n"; } } # warnings switched back on at end of scope
      If there is a reason you cannot use this technique in your inherited CPAN module please let us know.

        lexical warnings - perfect!

        Appreciate you taking the time to go through the code.

        Thank you!
      > To get out of the Use of uninitialized value I started adding the $blah AND $blah ... ... which is when I got totally caught up in this.

      IMHO thats wrong!

      Initialize a value, preferably at the moment where those variables are declared.

      Either "" or 0 depending on the way it's used in the line where you got the warning from.

      E.g.

      DB<115> use warnings; print " $z bla" Use of uninitialized value $z in concatenation (.) or string at (eval +39)[multi_perl5db.pl:644] line 2.

      Most likely means that $z is a string, so change my $z to my $z=""

      Cheers Rolf

        I subscribe to this opinion as well.

        To me, undef could mean a couple of things, depending on context:

        • if a function returns it, the function means to tell me
          • there's nothing more to tell you (e.g. when <$filehandle> has read the last line of the file, or when each %hash has returned the last key/value pair of the hash)
          • something went wrong (e.g. "you asked me to list your appointments on Feb 30th, but I couldn't find that date in my calendar?")
          • it wants to return a false value, where 0 or "" don't cut it (e.g. if you use some module to log in to your Amazon account and get the number of items on your wish list, it would be bogus for $amazon->items_on_wish_list to return 0 when $amazon->log_in(user => "muba", password => "soopr sekret!111") failed. 0 here would mean that my wish list is empty, whereas undef would mean "failed to fetch wish list")
          • it pulled its return value from some external source (a JSON object, a database record, whatever) and needs a way to represent the external source's notion of null or whatayamaycallit)
        • if I set a value to undef manually, I could do that because
          • I haven't come around to set it to something more definite yet (e.g. in writing code that reads one line from a file at a time, but has to remember the previous line it read, I'd write
            my $previous = undef; while (my $line = <$filehandle>) { chomp $line; ...; # process $line $previous = $line; }
            because initially, there is no previous line yet, and setting $previous to "" initially would make it look like the previous line was just an empty line. There is a difference between "no previous line" and "previous line was empty")
          • I need it to exist, but I really don't care about the value right now (e.g. I'm preparing the data for a to-be-created user account, which will have a birthday column, but I really don't need to set a definite value for that column while creating the account. The user can set that whenever she fees like. So I'll leave it undef for now)
          • I'm writing a function and I want to return undef for any or more of the reasons I mentioned above

        What all of these reasons have in common, is that they essentially mean to represent mu.

        If asked the question, "did you stop beating your wife?" then the answer "no" would imply that you still beat your wife. "Yes" doesn't cut it either, because it directly means that you used to beat her. But "mu" or "undef" would mean, "the question does not apply, I have never beaten her."

        Therefore, I think that if you're about to do something with a variable (print it, interpolate it, do arithmetic operations with it, throw it against a wall, feed it to your dog), you should either make sure it isn't undef, or explicitly check for its definedness.

        Struggling with this:
        my $data ; $data = ref($hash) eq 'HASH' ? $$hash{$name} : $hash ; $data = $$data{CONTENT} if ref($data) eq 'HASH' ;
        There is some circular reference also ... Guess I have to stick with catching __WARN__
Re: How come undef eq '' ??
by Anonymous Monk on Jan 30, 2013 at 19:20 UTC
    That's also why Perl calls itself a pragmatic language. Its purpose is to get stuff done, not to be an NP-complete problem or the expression of what some academic's notion of a perfect language ought to be. You're doing a string comparison. One value happens to be undefined. Do you blow up the program? No. You keep going, especially if you've not been told to be strict or to use warnings. An empty-string is the most plausible string representation of an undefined-value. Or at least it was at some time to someone. So that's what it does.
Re: How come undef eq '' ??
by vsespb (Chaplain) on Jan 30, 2013 at 23:50 UTC
    just replace
    if( $tmp and ( $tmp eq "" ) )
    with
    if( defined($tmp) and ( $tmp eq "" ) )

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1016083]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (3)
As of 2024-04-24 21:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found