perl-diddler has asked for the wisdom of the Perl Monks concerning the following question:

I was wondering (and thinking, w.r.t how code might be simplified), in the case where you compare an 'undef' value with any other value using literal (vs. numeric) operators, how it benefits people by having perl issuing a warning for comparing undef to something (including undef).

I was thinking on how one might silence that warning but NOT the warning if used in numeric comparisons (i.e. undef != $x), but couldn't think of an easy way since as the same warning message is used when concatenating string values.

I find the warning more useful in the case of trying to combine undef with a string, which people see most often when using print/printf to print a value that isn't defined. Without that warning, one wouldn't know the difference between a print w/undef vs. a print w/an empty string ('' or ""). Also, that usage can be trapped and compensated for in 1 place (the print routine -- that was the original motivation of the P module -- a safe way to print things without warnings, which usually are often set to terminate programs under the motto of "die early, die loudly (informatively)".

Under the current methodology, one has to use 2 checks to protect against that warning -- and it seems like that's one check too many for what, in my code, is a common case. That said, though, I realize there is a wide variety of coding idioms, and my find it hard to see such a question "objectively" -- so I thought I'd ask on here. How do you find those warnings use? I.e. what would be the compatibility issue with not issuing warnings in those circumstances?

Is that warning beneficial?

Note -- am talking about use of 'undef' with 'eq' and 'ne'. It's already the case that using 'undef' with 'or', 'and' and 'not' allow an operand to be 'undef' without accompanying warning messages.

How do people find the warning useful for 'eq'/'ne'?

  • Comment on Do people find warning for undef with string compare useful?

Replies are listed 'Best First'.
Re: Do people find warning for undef with string compare useful?
by Old_Gray_Bear (Bishop) on May 31, 2013 at 21:15 UTC
    For me the warning is useful.

    If a string is missing a value, that is an indication of a potential bug. The warning tells me that what I expected is not what I got. Either I have over looked someplace where a default should be set, or the incoming data is deficient (the User didn't fill in a field on the form, the database is missing a value, etc.) As a matter of defensive programming, I want to know that a value was missing, so I can run the bug to earth and fix it. And also determine why my test harness missed it. (The Spec said that User-ID-Alias is a required field, so why is it blank in the DB?)

    Now, whether the end-user of my code sees the warning is another matter. I write errors and warning to logs that I can check later. For code going into production for the first time, the first few days of those logs can be very enlightening (or horrifying....).

    ----
    I Go Back to Sleep, Now.

    OGB

      Now you realize, I mentioned only the "eq" and "ne" operators (cuz or/and/not already work on undef w/no warning).
      I'm not talking concatenation, or where you print it out.
      But specifically where you are testing the value against something else.
      In that case, do you still think, that if you are doing a comparison on it, you wouldn't notice that "empty"(undef) is or is not equal to some other string?
      How do you see it different than "and" "or" and "not"...

      i.e.
      string1 or string2 = true if one of them has length>0 etc...
      but it doesn't warn you about undef.

      It sounds like you were thinking concatenation... mixing strings w/strings... but if you are comparing, aren't you already testing the value? i.e.:

      > perl -we 'use strict;use P; P ((undef and 1) ? "yes": "");' no > perl -we 'use strict;use P; P ((undef or "") ? "yes": "no");' no > perl -we 'use strict;use P; P ((undef xor "") ? "yes": "no");' no > perl -we 'use strict;use P; P ((undef eq "") ? "yes": "no");' Use of uninitialized value in string eq at -e line 1. yes perl -we 'use strict;use P; P ((undef and 1) ? "yes": "no");' no > perl -we 'use strict;use P; P ((undef and 1) ? "yes": "no");' no > perl -we 'use strict;use P; P ((2 or undef ) ? "yes": "no");' y +es > perl -we 'use strict;use P; P ((2 xor undef ) ? "yes": "no");' yes perl -we 'use strict;use P; P ((2 ne undef ) ? "yes": "no");' Use of uninitialized value in string ne at -e line 1. yes Ishtar:/tmp> perl -we 'use strict;use P; P ((undef xor undef ) ? "yes" +: "no");' no perl -we 'use strict;use P; P ((not undef xor not undef ) ? "yes": "n +o");' no etc....

      So you already have the ability to use defined/undefined as boolean states, why do you think a warning when using it with equality, (eq or ne), is useful?

      Note I'm not talking about undef==3, or 2>=undef... or even undef cmp undef... as all of those *expect* some type of ordering or value.

      But if something is eq or ne, doesn't.

      Limiting it to that and considering we are only asking if what is in "$a" is the same as what's in "$b" (or not the same)...

      You still think the warning for that specific case is more useful than not?

Re: Do people find warning for undef with string compare useful?
by BrowserUk (Patriarch) on May 31, 2013 at 22:53 UTC

    Yes to the headline question. I've probably disabled it 3 or 4 times in (a guess) 25,000 scripts I've written.

    And then only temporarily until I worked out the proper way to prevent the warning rather than silence it.

    How do people find the warning useful for 'eq'/'ne'?

    Simple. If one of the variables in a comparison is undef, I either typoed, or I forgot to initialise it. A case of a class 1 beginner's error that I still make after 30 years doing this.

    And that warning tells me I made it (again), the first time I run the code; rather than it languishing as a latent bug that Sod's Law says will strike at exactly the worst moment.

    Anyone who disables it de rigor; or worse, skips warnings altogether as too much work, is simply kidding themselves.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Yes to the headline question. I've probably disabled it 3 or 4 times in (a guess) 25,000 scripts I've written.
      I don't know how to disable the warning for only the "eq" and "ne" operators. How do you do it without affecting other messages?
        { local $^W; # expression or statement using eq or ne (or lt or le or gt or ge + or cmp) here }

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Do people find warning for undef with string compare useful?
by tobyink (Canon) on May 31, 2013 at 20:59 UTC

    It's not one I find useful. I quite frequently disable uninitialized, void and once (and occasionally numeric) warnings. See also Four annoying warnings.

    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name
Re: Do people find warning for undef with string compare useful?
by smls (Friar) on May 31, 2013 at 21:47 UTC

    It is often annoying, though in some cases is does help find bugs.

    I don't like introducing "if defined" checks, as they blow up the code size and make it less readable. Luckily the // operator provides a slightly more concise solution that can be use in many (but not all!) situations where you want to do string-comparison on a variable that may be undef:
    Instead of...

    if ($possibly_undef eq 'Hello') { ...

    ...write:

    if ($possibly_undef//'' eq 'Hello') { ...

    Or of course "no warnings 'uninitialized';" if you want to disable it completely, but I don't usually do this.

      Unfortunately, // has lower priority than eq. You code is equivalent to
      if ($possibly_undef) { ...

      The correct syntax is

      if (($possibly_undef // '') eq 'Hello') { ...
      Which blows up the code size and makes it less readable.
      لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ
        Ah yes, you're right of course.
Re: Do people find warning for undef with string compare useful?
by vsespb (Chaplain) on May 31, 2013 at 21:39 UTC
    I find it useful. IMHO you should always check for undef and never compare undef with anything. If you expect your variable to act like 0 or empty string - just assign 0 or empty string.
      What if get two paired variables, and want to check that both are initialized, or both are empty or null strings?

      I don't necessarily want it to act like anything (0 or empty string) -- I just want it to compare as "not equal" to something that is defined, or "equal" to something that isn't -- with the caveat, that undef == undef, is only equal in a certain context -- i.e. they are both uninitialized.

      I would want it to compare different if I compared undef against 0 or the empty string, so assigning either of those other values would miss the point entirely.

        What if get two paired variables, and want to check that both are initialized, or both are empty or null strings?

        If '0' isn't a valid value

        if( ! $one == ! $two ) {

        If '0' is a valid value but '' is not

        if( ! length $one == ! length $two ) {

        If '' is also a valid value

        if( defined $one == defined $two ) {

        That middle case isn't sufficient on rather old versions of Perl because it used to be that length(undef) was '0' with a warning. Now length(undef) is undef so you'll only get the warning if you treat the length as a number.

        Some people replace '!' with '!!' because they use '!!' as an idiom for "I just care about whether it is true or not" or "convert to Boolean".

        [ Update: I've seen people use something like

        unless( $one xor $two ) {

        But I find it way too easy to end up making mistakes when you start using the ultra-low-precendence Boolean operators for things other than flow control (I've found quite a few such mistakes made by some of the most experienced Perl programmers I've worked with), so I don't really like that approach. (I also don't like 'unless' but I won't go into that here.) ]

        - tye        

        Then maybe you want 3-value-logic ?

        http://blogs.perl.org/users/ovid/2013/02/three-value-logic-in-perl.html

        http://en.wikipedia.org/wiki/Three-valued_logic

        For those very rare occasions, disable the warning locally.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Do people find warning for undef with string compare useful?
by Laurent_R (Canon) on Jun 01, 2013 at 10:17 UTC

    Yes, I find it useful.

    It is true that it is sometimes annoying in comparison tests where you just want to know, for example, if $a is equal to $b, not really caring whether one of the variable is undef, but the warning often tells you about a possible bug un your code or a possible anomaly in your data. It is good to have this information.

      Laurent, you think that having warning on for $a eq $b, gives you more useful warnings than false ones?

      How would that not apply to: $a and $b and $c -- as a quick way to check for that all are defined -- but it gives you no warning if $b=undef vs. $b='';

      I don't see how the eq case is any more helpful than the logical-only operators..?

      I just think of the amount of code out there that is written to avoid those warnings. Sure was a nice excuse for writing a replacement for Printf/sprintf/say that auto handles undef as args to a format by inserting 'undef' in the output - which I find alot less intrusive than a warning which, due to my own conventions, usually results in termination with traceback!... Don't many of us treat warnings as errors?

      I guess, personally, since my print's are all auto checked, I usually see undefs in debug and error statements -- though honestly, if someone gets a warning in their code over an undef, what that meand is that they didn't write code to check the value before making that comparison. How many such warnings are needed to get people to always program in checks where things possibly can be undef?

      Any value that can be undef -- *will* (eventually)...it's like a Murphism...;-)

      Relying on the warning to tell you that you left out a check doesn't seem real reliable, as there are alot of cases where no warning is given.

      But if people don't see that here, it sounds like we are stuck with it for the nonce....

        I don't see how the eq case is any more helpful than the logical-only operators..?
        Perhaps we should ask then why logical-only operators ignore undef, but not why other operators don't ignore it.
        I just think of the amount of code out there that is written to avoid those warnings.
        Really?
        a code to avoid warning and introduce bug:
        $x = '' unless defined($x)
        a code to just avoid warning;
        my $x = '';
        a code to avoid bug:
        defined($x) or confess;
        So you see 1st case in your code?

        a code with bug:
        mysub($user_data) { $user_$data->{invoice_number} ... } mysub({age => $user_age, inovice_number = $invoice_number}) # TYPO!
        a code which catches bug:
        mysub($user_data) { defined($user_$data->{invoice_number}) or confess; $user_$data->{invoice_number} ... } mysub({age => $user_age, inovice_number = $invoice_number}) # TYPO!

        Laurent, you think that having warning on for $a eq $b, gives you more useful warnings than false ones?

        No. I think that those warnings are useless more often than useful. But sometimes they are useful. And I still prefer to have them when they are useful (maybe only one case out of ten) because they tell me I have a bug in my code or something wrong in my data, even if I have to deal with the more common useless cases.

        I had very recently a case where I wanted to remove duplicates from a sorted file. I wrote something like this:

        my $previous_line; while (my $current_line = <$DATA>) { print $OUT $current_line unless $current_line eq $previous_line; $previous_line = $current_line; }

        And, of course I got a "false" warnings because $previous_line is not defined the first time through the loop. But, so what? How long does it take to change the first line of the code above to something like:

        my $previous_line = "";

        Ten seconds? I prefer to have these spurious warnings perhaps 9 times out of 10, because they tell me something really useful 1 time out of 10.