http://www.perlmonks.org?node_id=475348

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

I normally run my code with use warnings, but there are a couple of warnings that I find quite annoying. The first one is "Use of unitialized value in string blah blah blah ...", which occurs in common expressions such as

reftype $x eq 'HASH'
the subexpression in question (e.g. reftype $x) happens to evaluate to undef. I take care of this with the ol':
( reftype $x or '' ) eq 'HASH'

The other annoying warning is "Name ... used only once: possible typo...". For this I do this song-and-dance:

$DB::single = $DB::single = 1;

The thing is that, even though 99% of the time these warnings are just a PITA, ocassionally they do serve the intended purpose of flagging errors, so I'm reluctant to turn them off wholesale. And the solution of turning them off "locally", which usually requires rolling out a block just for the purpose, is even more awkwards than the kluges shown above.

But hope springs eternal!

Has any of you, by any chance, found a more clueful approach to dealing with these annoying warnings?

the lowliest monk

Replies are listed 'Best First'.
Re: Annoying warnings...
by jbisbee (Pilgrim) on Jul 15, 2005 at 22:01 UTC
    perldoc perllexwarn has a great tree representation of the warnings heirarchy so if you're ever in a situation where you want to turn off certain type of warning, you can see were it fits in the "tree" and only turn off the bit you need and not disable all warnings.

    -biz-

      I'm aware of this, but I'm on a (silly, I know) quest for ways to avoid these annoying messages without setting up a block solely for this purpose.

      BTW, when I want to find out the category of warnings to turn off I trigger the warning under diagnostics, whose output lists the categories of the warnings emitted. I don't think I've ever had reason to avail myself of the hierarchical organization of warnings; I always turn off the most specific level corresponding to a particular warning.

      the lowliest monk

Re: Annoying warnings...
by Zaxo (Archbishop) on Jul 15, 2005 at 20:19 UTC

    I think that the solution you imply of turning them off locally is the preferred one. Leave warnings on during development, and when you are sure you want to allow $foo to be undefined,

    { no warnings 'uninitialized'; # edit - corrected tag print "Say something about $foo.\n"; }
    That is a pain, as you say, but it makes you ask whether you really need the behavior you're warned of.

    Most warnings (not all!) represent some kind of useless behavior in a program. Cleaning them up nearly always improves the code.

    After Compline,
    Zaxo

Re: Annoying warnings...
by kwaping (Priest) on Jul 15, 2005 at 23:31 UTC
Re: Annoying warnings...
by gam3 (Curate) on Jul 16, 2005 at 00:02 UTC
    I think that the problem is at the point that $x is set and not at the reftype test. So you might try defining $x when it is created or set.
    my $x = $y || '';
    or you can set it before the test.
    $x ||= '';
    Or put the test in an if.
    if (defined $x) { reftype $x eq 'HASH' }
    -- gam3
    A picture is worth a thousand words, but takes 200K.
      print '$x is ', (defined $x && reftype $x eq 'HASH') ? '' : 'not', ' a hashref', "\n";
Re: Annoying warnings...
by schwern (Scribe) on Jul 16, 2005 at 23:13 UTC

    If a function has an interface you don't like, don't hack around it every time you call it and don't shut off the warning. Fix the function.

    use Scalar::Util (); sub reftype ($) { return '' if !defined $_[0]; return Scalar::Util::reftype($_[0]); }

    As for the "$Your::Global = 1" used only once problem, I hate that warning. I wrote up the your.pm module to work around it but its no less typing.

Re: Annoying warnings...
by schwern (Scribe) on Jul 16, 2005 at 23:27 UTC
    The other annoying warning is "Name ... used only once: possible typo. +..". For this I do this song-and-dance: $DB::single = $DB::single = 1;
    There's no warning if the variable already exists, which seems correct to me. This does not warn.
    use DB_File; # Just some global in DB_File. $DB_File::db_version = 42;
    This does warn.
    use DB_File; $DB_File::wibble = 42;
    PS The warning happens at compile time so the variable has to exist at compile time. This means:
    require DB_File; $DB_File::db_version = 42;
    does warn.
Re: Annoying warnings...
by adrianh (Chancellor) on Jul 16, 2005 at 14:56 UTC
    The other annoying warning is "Name ... used only once: possible typo...".

    use vars or our would be my preferred solution to this warning.

Re: Annoying warnings...
by Smylers (Pilgrim) on Jul 16, 2005 at 10:03 UTC
    ( reftype $x or '' ) eq 'HASH'

    Has any of you, by any chance, found a more clueful approach to dealing with these annoying warnings?

    Ugg — that's ugly, and quite obfuscated: it isn't apparent from glancing at that code exactly what it does or that it's written like that to avoid a warning. Creating a new block with that particular warning disabled at least has the advantage of making it absolutely clear what you're doing.

    A clearer way of doing the above without a block is simply to test $x for being true (since all refs are true) first — this avoids the mysterious empty string constant and translates quite well into the equivalent English:

    $x && reftype $x eq 'HASH'

    (By the way I think it's slightly insulting of you to ask if any of us have suggestions for this "by any chance" — implying that we only discover things randomly rather than through having intelligence or talent!)

    Smylers

      Ugg — that's ugly, and quite obfuscated: it isn't apparent from glancing at that code exactly what it does or that it's written like that to avoid a warning

      I disagree. That's a common idiomatic way of resolving the problem of false/undef in some expressions and I see it in lots of code.

      The only problem with this strategy is that it sometimes gets used in places where non-undef false values like '0' shouldn't be ignored, which can lead to odd bugs. Not a problem in this instance.

      $x && reftype $x eq 'HASH'

      As already pointed out this breaks for true non-reference values.

      In this particular instance I'd probably make it a bit more explicit the exact thing I'm looking for:

      # I want a reference whose type is 'HASH' ref $x && reftype $x eq 'HASH';

      A clearer way of doing the above without a block is simply to test $x for being true (since all refs are true) first...

      Well, not quite. The code you proposed would still result in a warning if $x is 1, for example:

      % perl -MScalar::Util=reftype -we '$x=1; my $y=($x and reftype $x eq q +(HASH))' Use of uninitialized value in string eq at -e line 1.
      What needs to be tested is that the value returned by reftype $x is defined. So your solution should be cast as
      ...( reftype $x and reftype $x eq 'HASH' )...
      or, two avoid the duplicate calls to reftype:
      { my $temporary_variable = reftype $x; ...( $temporary_variable and $temporary_variable eq 'HASH' )... }

      Update: Fixed missing "$x and " in the one-liner.

      the lowliest monk

Re: Annoying warnings...
by sfink (Deacon) on Jul 16, 2005 at 17:37 UTC
    I run into the $DB::single = 1 problem a lot too. I do the same as you, but come to think of it, this somewhat ugly snippet would work too:
    ${$DB::{single}} = 1;