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

Hi Monks,

If each of the two methods below is called without any values e.g. meth1(); , meth2 triggers the "Use of uninitalised values in ... " warning.

use strict; use warnings; use diagnostics; sub meth1 { my $var1 = shift || 0; my $var2 = shift || 0; return $var1 if $var1 > $var2; return $var2; } sub meth2 { my ($var1, $var2) = @_; # Do we need to do this all the time? # $var1 ||= 0; # $var2 ||= 0; return $var1 if $var1 > $var2; return $var2; }
Are there better ways around the problem with both methods?

Thanks in anticipation :)

Replies are listed 'Best First'.
Re: Dealing with Use of uninitialised Values warning
by gaal (Parson) on Nov 20, 2004 at 07:02 UTC
    What diotalevi said; and in the case of these particular functions, you can look at the desired semantics and do something like:

    return 0 unless @_; return $var1 if @_ == 1;

    This may seem like a lot of work to you, but at least it makes explicit the behavior of your code with, um, nonstandard arguments.

    And in regard to ||=, personally I think it's a pretty elegant operator, but perhaps you might like this better:

    my $var1 = shift || 0; my $var2 = shift || 0;
    Again, this makes things *more* explicit than they were. Maybe that isn't what you had in mind when you said "better" :)
      Thanks, gaal!

      Those are good enough. I wasn't sure whether other solutions existed that were "better" than what I knew of.

Re: Dealing with Use of uninitialised Values warning
by diotalevi (Canon) on Nov 20, 2004 at 06:27 UTC
    In general it is not a problem that your functions throw this error. Its a warning sign that there's something wrong with the code that is calling these functions. If you really want to allow these functions to accept less than the required parameters then you should be using $foo = 0 if not defined $foo; settings.
Re: Dealing with Use of uninitialised Values warning
by Your Mother (Archbishop) on Nov 20, 2004 at 19:02 UTC

    You could also do this:

    use warnings; no warnings 'uninitialized';

    It's handy, especially in CGI, for situations like if ( $param_this =~ /that/ ) {}, which otherwise has to be if ( $param_this and $param_this =~ /that/ ) {} to avoid the warnings. It's sort of a DWIW kludge but since you're doing comparisons without explicitly checking what sort of thing you're comarping ("e" > 6, for example), it might be fine for what you're doing.

      Thanks, Your Mother!

      Ah, I see. I suppose we can place "no warnings 'uninitalised'" at the point where it should take effect. Am I right?

        That's right. It scopes the effect. But you will have to use the proper US spelling. :)

Re: Dealing with Use of uninitialised Values warning
by Zaxo (Archbishop) on Nov 21, 2004 at 01:38 UTC

    You've gotten good advice on the uninitialized value warnings.

    I'd just like to note an alternative way to write this. Your max function can be written in terms of the trinary operator,

    sub meth3 { my ($first, $second) = map {$_ || 0} @_; $first > $second ? $first : $second; }
    I've used map as an alternative to the separate ||= statements. This function is neither worse nor better than yours, other than being smaller and maybe faster. Trinary has advantages when writing lvalue subs, since trinary op produces an lvalue.

    After Compline,
    Zaxo

      Thanks, Zaxo!

      I like both your map and trinary solutions :) The map is particularly enlightening, because I was using a couple of shift's to achieve that effect.

Re: Dealing with Use of uninitialised Values warning
by TedPride (Priest) on Nov 20, 2004 at 13:28 UTC
    I didn't get any errors from the first method. The second did give an error, but both work fine when rewritten as follows:
    sub meth1 { return 0 if $#_ == -1; return $_[0] if $#_ == 0 || $_[0] > $_[1]; return $_[1]; }
    (no need to use named variables btw - just work with the contents of the input)