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

Hello all!!! I've been having a little bit of trouble with the exists and defined functions. When I try to use the expression: print DATA "\+$exp[1]" if exists $exp[1]; and so on, but I get this message "exists operator argument is not a HASH element" I have no idea what's going on. Help!


Here's all code:
#!/usr/local/bin/perl print "Content-type: text/html\n\n"; use CGI::Carp qw(fatalsToBrowser); #use strict; use CGI; my $q = new CGI; my @exp = $q->param("explorer"); my $hoursworked = $q->param("hrswrked"); my $name = $q->param("name"); my $num = @exp; (my $sec,my $min,my $hour,my $mday,my $mon,my $year,my $wday,my $yday, +my $isdst)=localtime(time); my $month = $mon+1; my $year1 = $year+1900; my $date = "$month\/$mday\/$year1"; my @months = qw(January February March April May June July August Sept +ember October November December); if ($q->param("submit")) { if (($hoursworked eq "") || ($num == 0)) { print <<"PrintTag"; <html><head><title>Insufficient information</title> </head><body bgcolor = "white" text="black" link="black"> <BASE HREF="http://nbpdexplorers.port5.com/"> <br><br><center><h2>Insufficient information</h2></center> <blockquote><blockquote><center><p><b>The following field(s) were empt +y:<br><br> <table> PrintTag if ($hoursworked eq "") { print "<tr><td><li><b>Hours Worked</b></li></td></tr>"; } if ($num == 0) { print "<tr><td><li><b>Explorers</b></li></td></tr>"; } print <<"PrintTag"; </table></p></center></blockquote></blockquote> <center><h3>Please click the \'Back\' button on your browser to try ag +ain</h3></center></html> PrintTag exit; } @exp = sort(@exp); @date = split(/\//, $date); $month = shift(@date); $month--; $month = @months[$month]; open(DATA, ">>/host/n/b/p/p/o/r/nbpdexplorers.port5.com/cgi-bin/data2. +txt") or die "Cannot open database file: $!"; flock(DATA, 2); print DATA "$month\+$exp[0]"; print DATA "\+$exp[1]" if exists $exp[1]; #print DATA "\+$exp[2]" if exists $exp[2]; #print DATA "\+$exp[3]" if exists $exp[3]; #print DATA "\+$exp[4]" if exists $exp[4]; #print DATA "\+$exp[5]" if exists $exp[5]; #print DATA "\+$exp[6]" if exists $exp[6]; #print DATA "\+$exp[7]" if exists $exp[7]; #print DATA "\+$exp[8]" if exists $exp[8]; #print DATA "\+$exp[9]" if exists $exp[9]; #print DATA "\+$exp[10]" if exists $exp[10]; #print DATA "\+$exp[11]" if exists $exp[11]; print DATA "\+$hoursworked\n"; } flock(DATA, 8); close(DATA); } print <<"PrintTag"; <html><head><title>Record Accepted</title> </head><body bgcolor = "white" text="black" link="black"> <BASE HREF="http://nbpdexplorers.port5.com/"> <br><br><center><h2>Request Add Record Accepted</h2></center><br><br> <blockquote><blockquote><center><p><font size="+1">To check hours work +ed status or to edit explorer listing, click <a href="http://nbpdexpl +orers.port5.com/cgi-bin/mainpage.cgi?name=$name">here</a></font></p>< +/center></blockquote></blockquote> <br><br><br><br><br><br><br><br><br><br><blockquote><blockquote><cente +r><p><font size="+1"><a href="http://nbpdexplorers.port5.com">Click H +ere To Log Off</a></font></p></center></blockquote></blockquote> PrintTag

Replies are listed 'Best First'.
Re: exists and defined functions
by rob_au (Abbot) on Nov 20, 2002 at 21:12 UTC
    Firstly, to correct the record, the exists function can be used on arrays to test the presence, defined or otherwise, of an array element.

    As of Perl 5.6.0, the exists function can be used on arrays to test the existence of an element within an array. For example:

    my %hash = ( 'key' => 'value' ); print "exists \$hash{'key'}\n" if exists $hash{'key'}; my @array = ( 'value' ); print "exists \$array[\$index]\n" if exists $array[0];

    Under Perl 5.005.03 this code results in an error:

    exists operator argument is not a HASH element at test-5.00503.perl li +ne 7.

    Whereas, under Perl 5.6.0 or later, the code executes without error:

    exists $hash{'key'} exists $array[$index]

    As such, your solution here will be to employ a newer version of Perl, rewrite your code to use the defined function as suggested by the other posts in this thread, or check your index against the value of $#exp (the index of the highest array element).

     

    perl -e 'print+unpack("N",pack("B32","00000000000000000000000111101000")),"\n"'

      Note that the change to make exists work on array elements was widely disliked and that I consider it, quite simply, a mistake and nothing more. Unfortunately, this mistake was made by Larry and he makes the rules. This is one of his rare bad decisions (nobody's perfect).

      Please don't use exists on array elements as the most likely result will be confusion and bugs. exists makes sense on hash elements because it distinguishes the case of the key being present with a value of undef from the case of the key not being present. For arrays, the distinction is much more subtle and is something that should never be worried about (I'd go into more details on it but I follow my own advice and don't worry about it).

              - tye
Re: exists and defined functions
by tadman (Prior) on Nov 20, 2002 at 21:30 UTC
    As pointed out by rob_au, you can use exists on an array in Perl 5.6 or better. If you're forced to use something as antiquated as 5.005, then consider this:
    print "+$exp[1]" if ($#exp >= 1);
    The element at index 1 may be undef, though, and give you warnings.

    The point of your question, though, is to get these listed properly. What about something simpler, such as this:
    print DATA join('+', $month, @exp, $hoursworked)."\n";
    This will put plus signs between any values in @exp. I think join is a much better solution than a whole whack of print statements.

    Just a few other remarks too:
    • The only characters you need to escape within double quotes are other double quotes ("\""), literal $, @, \, and things like newline ("\n"). The rest are generally fine.
    • Recycle your variables instead of making new ones. For example: $year += 1900 instead of my $year1 = $year + 1900 since you don't really use $year otherwise.
    • Declare several variables with a single my like this: my ($sec, $min, $hour) = ...
    • Indent your code to make it more readable. It might seem like a trivial matter on a program like this, but when it grows, you'll appreciate it.
Re: exists and defined functions
by robartes (Priest) on Nov 20, 2002 at 20:58 UTC
    exists operates on hashes only (as the error suggests): it checks whether the key given exists in the hash. To test for the existence of an array element, use defined:
    print DATA "\+$exp[1]" if defined $exp[1];
    The above code snippet is untested, BTW.

    CU
    Robartes-

Re: exists and defined functions
by arrow (Friar) on Nov 20, 2002 at 22:11 UTC
    Hey, thanks insensate, robartes, rob_au, and tadman for your help. Thanks to you guys, my scipt is finally working. I am forever indebted to you.

    print "Thank you**99";
Re: exists and defined functions
by insensate (Hermit) on Nov 20, 2002 at 20:49 UTC
    exists() is a function used by hash data structures. You are calling it on array elements. Try:
    print DATA "\+$exp[1]" if $exp[1];
    That will print as long as the value in $exp[1] is not 0.
    update:Response tailored to user's evident < 5.6 version of perl...see below comments for versions >= 5.6
Re: exists and defined functions
by arrow (Friar) on Nov 20, 2002 at 22:14 UTC
    oops, and tye. Once again, thanks a whole bunch