Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Unintialised value?

by eoin (Monk)
on Jan 24, 2004 at 21:50 UTC ( [id://323872]=perlquestion: print w/replies, xml ) Need Help??

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

Monks just a quick question here.
The following code produces a
 Use of uninitialized value in numeric eq(==) at index.cgi line 60.
error. The corresponding line numbers have been included.
#57 my %pages = ("index" => '1', #58 "me" => '1', #59 "stuff" => '1', #60 "links" => '1'); #61 my $page = shift; #62 exit 0 unless $pages{$page} == '1';
Now the only thing that confuses me is that the line on which the error occurs hasn't got a numeric eq (==) on it and also the lines around it havn't got any uninitialised values on them.
I'd appriciate any help.
Cheers

Go raibh míle maith agat, Eoin...

Replies are listed 'Best First'.
Re: Unintialised value?
by Vautrin (Hermit) on Jan 24, 2004 at 22:41 UTC

    If you use strict; use warnings; whenever you try to compare an undefined value it will yelp. This is great to do, but if you want to fix that warning you should let perl know you expect the possibility of an undef value by testing for an undef value (and only performing concatanation, regular expressions, or anything else with it) if it's defined, i.e.:

    # note that we have to check if its defined # because it's possible it could be 0, and false #62 exit 0 unless ((defined ($page)) and (defined($pages{$page})) and ($pages{$page} == '1'));

    You should note that you are shifting from @_ to set $page == undef; especially on this little bit of test code. So if @_ is undefined then you'll get those warnings. You can turn off warnings for uninitialized values by using:

    NOWHINING: { no warnings qw (uninitialized); my %pages = ("index" => '1', "me" => '1', "stuff" => '1', "links" => '1'); my $page = shift; exit 0 unless $pages{$page} == '1'; }

    Just be careful with the above code because:

    1. The no warnings qw(uninitialized); is declared within the NOWHINING: block so as to keep its scope only for the offending code. You could extend this to your entire program by using no warnings qw(uninitialized); at the top of your script, but this becomes dangerous because you want to know when uninitialized values are being used.
    2. The %pages and the $page variables are only valid within the {}s. This may or may not be an issue. Adjust your scope accordingly.
    3. Is @_ supposed to contain undef values? If it isn't you've got bigger problems.
    4. because @_ is "magical" as soon as you use any function that modifies @_ it can on change you. I recommend you never use it unless where the @_ comes from is clear from the code.
    5. Use something like my @arguments = @_; at the beginning of wherever you get the @_ from so that any sub that is called doesn't modify @_ on you.
    6. perl -e 'use strict; use warnings; my $foo; print $foo;' and perl -e 'use strict; use warnings; undef =~ m/foo/;' will show you some ways you can get and reproduce that error.

    Good luck!

    Vautrin
Re: Unintialised value?
by blue_cowdawg (Monsignor) on Jan 24, 2004 at 22:06 UTC

    I just tried to duplicate your problem as follows:

    use strict; use warnings; &foo('gronk'); sub foo { my %pages = ("index" => '1', "me" => '1', "stuff" => '1', "links" => '1'); my $page = shift; exit 0 unless $pages{$page} == '1'; }
    and got a similar (or same) result.
    [peter@kennel tmp]$ perl test_eq.pl Use of uninitialized value in numeric eq (==) at test_eq.pl line 13.
    The good/bad news is that line 13 does correspond to the == operator.

    What value is $page set to?


    Peter L. Berghold -- Unix Professional
    Peter at Berghold dot Net
       Dog trainer, dog agility exhibitor, brewer of fine Belgian style ales. Happiness is a warm, tired, contented dog curled up at your side and a good Belgian ale in your chalice.
Re: Unintialised value?
by neuroball (Pilgrim) on Jan 25, 2004 at 01:11 UTC

    Hello, you might want to learn about the ins and outs of debugging.

    Most of the information can be found in the perl documentation by using perldoc perldebug. If you want to invest a bit more time and effort into debugging you might want to get a copy of Perl Debugged.

    Now back to your problem: You might want to print $page between line 61 and 62 and then exit (So that you actually see the result of your CGI).

    The only problem that I see with your script, not knowing the input, is that $page might have been set to undef and then used as hash key, which returns also undef and breakes the if-statement.

    Btw. The line numbers returned by errors and warnings are more of a semi-intelligent guess-timate of perl. It just gives you a point to start... but it isn't like an X on a treasure map.

    /oliver/

Re: Unintialised value?
by davido (Cardinal) on Jan 25, 2004 at 07:40 UTC
    Nobody seems to have mentioned this, but you should be using exists to check for the existance of a hash key. In your example code, every key that has been brought into existance has been initialized with a value of 1. So one obvious potential problem is that you're checking for value in a key that doesn't exist. Hense, you get the warning about an uninitialized value. Is this a surprise? This is exactly what the exists function is for.

    my % pages = ( 'index' => 1, 'me' => 1, 'stuff' => 1, 'links' => 1 ); my $page = shift; exit 0 unless exists $pages{$page} and $pages{$page} == 1;

    This will not generate the uninitialized value warning, because the right hand side equality test only gets evaluated if the left side of the logical short-circuit 'and' evaluates to truth first (if the hash key exists).

    If you happen to be in a situation where the key might exist but without any initialized value, you could chain a defined in there...

    exit 0 unless exists $pages{$page} and defined $pages{$page} and $pages{$page} == 1;

    Not terribly elegant, but it does take into consideration all the possibilities.


    Dave

      exit 0 unless exists $pages{$page} and defined $pages{$page} and $pages{$page} == 1;

      Is the exists test really necessary here? Shouldn't the test for defined suffice? In my (admittedly limited :-) experience, a perl variable that is defined necessarily exists, so:

      exit 0 unless defined $pages{$page} and $pages{$page} == 1;

      should suffice.

      But perhaps I'm missing something, and you can show some instance where both tests are needed?

      TIA

      dave

        Is the exists test really necessary here?

        Well, it depends. There are four things that a hash element can be (in a simple world). True, False, Undefined, or Nonexistant.

        I consider it at least bad style, and a bad habbit to get into, to use defined to test hash elements that may not even exist. Yes, you will not get a warning for doing so. But let's keep things clear; does a key exist or not, is it defined or not, is its value true or not?

        Consider the following:

        | * * * V a l u e s * * * Evaluation | 1 or 'X' | 0 or '' | undef | nonexistant -----------+-----------+---------+-------+------------- boolean | True | False | False | False defined | True | True | False | False exists | True | True | True | False

        So the only way to be sure whether you're looking at an undefined element, versus a nonexistant element, is to use exists. If you don't care whether it exists or not, only whether or not it's got a value, use defined, but in the example the OP gave us, he seemed to want to exit if a hash element didn't exist, and exists is the right thing for that job. I find it best to not be ambiguous about things that may bite me later.


        Dave

Re: Unintialised value?
by Coruscate (Sexton) on Jan 25, 2004 at 05:36 UTC

    Though perl will correct your "error", I'll just point out that you should be using 'eq' to compare strings, and '==' to compare numerical data. In your specific example, you won't find a difference, because perl will convert the string '1' to numerical 1 for you, but you shouldn't expect perl to think for you. :)

    # shouldn't use this unless $pages{$page} == '1'; # should use this (keep quotes, use 'eq') unless $pages{$page} eq '1'; # or use this (keep '==', remove quotes) unless $pages{$page} == 1;

      Fixed that problem but now have this:
      [Tue Jan 20 18:48:39 2004] [error] [client 159.134.228.95] Premature end of script headers: /home/eoin/public_html/cgi-bin/index. +cgi Can't open perl script "^M": No such file or directory
      Any ideas??

      Eoin.

        Some background info: (You may or may not know this -- included for completeness) CGI is a protocol whereby executable programs can be run on a web server in a controlled enviornment which allows them access to the outside world as securely as possible. (Thus, CGI != Perl as some people think. Basically, a CGI script has to do all the work Apache or another web server would do when sending web pages. This means reading in GET variables from $ENV, and outputting the proper headers. (This is unlike a language like PHP which does all this for you unless you tell it not to)).

        So whenever a CGI script sends a web page to a client browser it must print the following header first: (This is a bare minimum. There are many more headers that can be sent. Download a copy of Mozilla and install LiveHTTPHeaders. This lets you watch the headers sent back and forth between the browser and server -- which is useful for learning and debugging).

        use strict; use warnings; #$content_type is the /mime/ type my $content_type = 'text/html'; print "Content-type: $content_type\n\n";

        Notice that the headers end with a blank new line. And these headers must be the first thing your script outputs, and they must be valid headers. And, of course, content type can change depending on whether you have an image (i.e. "image/jpeg" or "image/gif"), or XML (i.e. "application/xml" ("text/xml" is considered deprecated because it defaults to ASCII and not UTF)).

        Now, usually you'll write a function to do all of this for you, or you'll use CGI; in your script so that you don't have to create headers manually. But you still need to print out the headers, in the case of the CGI module it would be:

        use strict; use warnings; use CGI; my $content_type = 'text/html'; my $web_page = "<h1>hello world</h1>"; my $CGI_obj = $CGI_obj->new; # either: print $CGI_obj->header($content_type); # or (uncomment 1 line below and comment 1 line above) # print "Content-type: text/html\n\n"; print $CGI_obj->start_html; print $web_page; print $CGI_obj->end_html;

        The error message in your log files is saying that no headers were printed. This should be the very first thing your script outputs If you don't print them before anything else and use valid headers you will get that error. (Hint: use CGI.pm so you don't need to learn the entire HTTP standard. It's got lots of options for headers you probably never even knew existed).

        Also, if Carriage Returns (^Ms) which are a staple of Microsoft files are evil in the unix world. Make sure you are saving your scripts in Unix file format. If you don't, no interpreter will be found, and you'll get errors. That may be what that second error is.

Re: Unintialised value?
by Skeeve (Parson) on Jan 24, 2004 at 22:14 UTC
    You're two lines off because it's a CGI. I suppose because of this at least the first line (#!/.../perl) isn't seen by perl.
      Can you expand on that? There's nothing special about a CGI script, though there are several special ways someone may be running a CGI-like script. If something like mod_perl is making the line numbers off like that, it's a bug, and should be fixed use of a #line directive.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others pondering the Monastery: (4)
As of 2024-04-25 23:28 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found