In my eternal search for perfection and nirvana (well, actually I'm just frustrated with myself), I've been trying to figure out how to how to write my code so I never get those annoying "uninitialized value" warnings that appear far to frequently for me.

After searching around PM for a while today, it seems the most common way to do this is by using:

if (defined $value) { ..... }
however, there are moments where that is inconvienient (I'm not lazy, just efficient--OK, so I am lazy). What are other ways to ensure that I write my code right the first time, to avoid this error?

xiexie,

melguin

Replies are listed 'Best First'.
Re: on to better coding (no uninitialized values)
by Masem (Monsignor) on Aug 23, 2001 at 21:05 UTC
    Assuming that your undefined values are coming in from subroutine calls, or from something like CGI.pm, one way I do it is to set a default value for it using the powerful ||= operator:
    sub do_something { my ( $file ) = @_; $file ||= "default.txt"; ... }
    If $file is defined, no further action is taken, since || short-circuits out on the true value. Otherwise, it sets $file to the default name given. Any time further, there's very little chance that $file will be undef'd.

    The only time this doesn't work is if a value 0 or the empty string ('') is passed, since these also evaluate to false. In cases where these are possible values, I then do defer to defined to make sure that the values aren't overwritten.

    -----------------------------------------------------
    Dr. Michael K. Neylon - mneylon-pm@masemware.com || "You've left the lens cap of your mind on again, Pinky" - The Brain
    It's not what you know, but knowing how to find it if you don't know that's important

      The ||= idiom is useful for providing default values. However I've seen programmers use it extensively, precisely to get rid of the use of uninitialized value warning. I think that is not a good strategy, because it will hide bugs. A variable that is used without having been initialized illustrates a logic bug, and the warning comes in handy to warn us of this bug. Adding ||= "" to the offending line gets rid of the warning, but not of the bug. Indeed it is a useful idiom if the concept of a default value makes sense for a particular variable, but it shouldn't be abused.
      I prefer to use something like:
      sub do_something { my $file = shift || 'default'; }

      since this is also conveniently converted to perform an action:
      sub do_something { my $file = shift or warn "empty parameter\n"; }

      YMMV.
(dws)Re: on to better coding (no uninitialized values)
by dws (Chancellor) on Aug 23, 2001 at 22:31 UTC
    I've been trying to figure out how to how to write my code so I never get those annoying "uninitialized value" warnings that appear far too frequently for me.

    If you're getting these frequently, then you have enough data to look for patterns. Without knowing what the underlying problem patterns are, you run the risk of hiding problems deeper by, for example, always manually initializing variables.

    Getting an "uninitialized value" warning tells you that you managed to get to a specific place in your code without having a value assigned to a variable (or element of an array or hash) at a value is now needed. (That's the "well, duh" part.) What's more interesting is why?

    • If the value should have been passed in to a subroutine but wasn't, you may be having problems with either structuring or invoking your interfaces. Using funciton prototypes might help.
    • If a value should have been established within the routine in preceeding code, perhaps you're suffering from some difficulties in structuring conditional logic (e.g., missing else clauses, or gaps in a chain of conditions). Here, preinitializing the variable might hide the problem.
    Better, I think, to seek first to understand why you're having this problem, rather than reaching immediately for a coding solution.

    I had a problem early in my career with a certain pattern of conditional logic. I'd try to write code in a certain way, and my brain would basically hit a blind spot. Debugging was a bitch, because my brain wasn't untangling what it was seeing. Only by stopping to analyze the problem (with some help) was I able to make it go away.

Re: on to better coding (no uninitialized values)
by dragonchild (Archbishop) on Aug 23, 2001 at 21:03 UTC
    The first thing would be to use strict. First line (after the shebang) should be:
    use strict;
    Probably the most important line in your script. That will force you to declare your variables with my (or our or use vars).

    Another option is to, when you declare your variables, to initialize them. Something along the lines of:

    my $foo = 0;
    If you do that, that will definitely fix your unitialized problems.

    ------
    /me wants to be the brightest bulb in the chandelier!

    Vote paco for President!

      The first thing would be to use strict.

      I thought this was a given (along with -w), but I suppose not, huh?

Re: on to better coding (no uninitialized values)
by Maclir (Curate) on Aug 23, 2001 at 22:16 UTC
    This reminds me of COBOL programming on IBM mainframes in the early 1980's - if you did not initialise numeric values before using them in a condtional, you would get a program abend and a dump (the good old OC7 abends, for any other OS/370 programmers out there). So the standard way we woudl declare our variables was something like:
    WORKING-STORAGE SECTION. 05 SOME-VARIABLE PIC 9(10) USAGE COMP VALUE 0.
    That solves one problem. Now the other issue to resolve is "why is an unitialised variable being referenced in your code"? There are probably two causes:
    1. The value is optional - say from a HTML form. So then the corresponding value in the %param hash will be undefined. Several solutions:
      1. set a default value on the HTML form itself;
      2. have a loop early in your form processing program that iterates across every element in %param and, if undefined, defines it to some value; or
      3. use the if (defined $param{some_param}) { construct.
    2. You have a bug in your program, or in the program calling the routine. A good practice to get into is to have a "preprocessing" validation section first in a program - did we get all the information we need, are the values sensible, and so on. If the input fails the validation - including mandatory values that were not supplied (and hence undefined), your routine should fail - with suitable diagnostic messages.

    The bottom line is, there is probably no universal, safe "catch all" to prevent the uninitialised value message. As part of your code design, you need to consider what it means if a variable is undefined - is it merely an optional value, and if it is undefined, we can ignore that (and skip some processing), or is there a deeper problem in the program?