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

A long while back I hired programmers from rentacoder to write scripts for me and now when I look back at them I noticed how screwed I was *sigh*. My programmer evidently didn't hear about using strict so I spent the last three hours making all the needed changes (there's a bug somewhere that I'm trying to trap). I've come across a question, how can you make a variable inside of a loop constant?
unless ($title) { $errorcount = 1; $error_title = "<br><font color='red'>Please enter a title.</font>"; } unless ($url) { $errorcount = 1; $error_url = "<br><font color='red'>Please enter a valid address.</fon +t>"; } unless ($description) { $errorcount = 1; $error_description = "<br><font color='red'>Please enter a description +.</font>"; } unless ($keywords) { $errorcount = 1; $error_keywords = "<br><font color='red'>Please enter some keywords.</ +font>"; } if ($errorcount) { print errors blah blah }
$errorcount is only initialized and defined in each unless loop so by the time it gets to if ($errorcount) { that data is lost. My question is how do I keep $errorcount's data or is there a better way to write this?

Replies are listed 'Best First'.
Re: Constant variables
by integral (Hermit) on Apr 27, 2003 at 08:33 UTC

    unless isn't a looping construct, it's a branching/control construct, but that's not important, what is important is the scoping of the $errorcount variable (see Coping with scoping as usual). You need to define the variable in the containing scope of the unlesses and the if.

    If you declare the variable once within each block you will be accessing a different variable in the block. If you want to access the same variable it must be declared at a containing scope so that it is visible (a containing lexical scope if you're using lexicals, and a containing dynamic scope if you're using package globals, which you shouldn't be for something like this)

    --
    integral, resident of freenode's #perl
    
Re: Constant variables
by Aristotle (Chancellor) on Apr 27, 2003 at 14:08 UTC
    Besides your problem (which, as Abigail-II notes, is not apparent from the piece of code you posted), that is a horrible construct - flag variables like $errorcount are a red flag, as are collections of $foo_bar, $foo_baz, $foo_quux variables. An initial cleanup leads to:
    sub print_error { my $message = shift; print "<br><font color='red'>$message</font>"; # etc.. } unless($title and $url and $description and $keywords) { $title or print_error "Please enter a title."; $url or print_error "Please enter a valid address."; $description or print_error "Please enter a description."; $keywords or print_error "Please enter some keywords."; # ... }

    You could still do a lot better if $title, $url etc where all stored in a hash. See Mark-Jason Dominus' excellent Program Repair Shop and Red Flags article series on Perl.com.

    Update: thanks to The Mad Hatter for catching a small mishap. (s/$shift/\$message/)

    Makeshifts last the longest.

Re: Constant variables
by dub4u (Sexton) on Apr 27, 2003 at 08:43 UTC
    This isn't about constantness of $errorcount, it is about $errorcount's scope. To make the scope of $errorcount extend to the whole code, declare it before the first unless block.
    my $errorcount = 0; unless ($title) { ...
    The variable name 'errorcount' also suggests, that you want to count how may errors there are. Currently, each unless block sets the errorcount to 1, disregarding how many errors where counted in prior unless blocks. So within the unless blocks, you want to change the assignment to $errorcount such that it acts as a counter:
    # $errorcount = 1; # probably not what you want # better: $errorcount = $errorcount + 1; # or $errorcount += 1; # or $errorcount++;
Re: Constant variables
by Abigail-II (Bishop) on Apr 27, 2003 at 11:55 UTC
    Well, you are wrong. Variables don't lose their value upon exiting the block they get their value in (coding would be much harder if that was the case). Variables lose their value (or existance) when exiting the block they were declared (with my) or localized (with local). But that's not happening in the code you are quoting.

    Abigail

      "Well, you're wrong."

      Laziness, impatience and hubris may go a long way to getting the job done, but I don't think Larry was talking about interpersonal skills. Many people, especially those who are asking for help from those who have more experience, are turned off by this kind of attitude. Saintly may be your technical skills, but walkest thou friendly amongst the throng, I beseech.

      --
      [ e d @ h a l l e y . c c ]

        halley, some people simply don't know how to offer constructive criticism without sounding harsh and don't see the point in doing so. Abigail is one of those and I think will always be so. There's not much point in trying to change the leopard's spots.

        Wally Hartshorn

        (Plug: Visit JavaJunkies, PerlMonks for Java)

        Damn, did you just sign up with AOL today? You actually think saying "Well, you're wrong" when helping someone out online is mean? Abigail-II donates time to help someone out, gives a perfectly good answer in a direct fashion, and you have the nerve to suggest that's impolite? Have you ever seen an online discussion before? This is as good as it gets buddy. I wish more people were this straightforward. I can't stand wasting my time reading the sugar-coated, carefully phrased, drivel that I so often get in response to questions. I just want an answer damn it! Enclose it in <youareafreakingmoron> tags if you need to, I don't care in the slightest and I'll still thank you.

        Sheesh, I didn't know there were still any left.

        What's your point? That he was right? Or that we should lie? Or that we should be like sales people and sugarcoat everything?

        Come on, this isn't kindergarten. If you can't stand the heat, stay out of the kitchen. If you can't face the fact you might be wrong, don't ask questions here.

        Grow up.

        Abigail

          A reply falls below the community's threshold of quality. You may see it by logging in.
        You're right, I seem to have forgotten the basics in years of useing strict; - thanks for the correction.
    Re: Constant variables
    by Your Mother (Archbishop) on Apr 28, 2003 at 03:03 UTC
      Related to the sample Aristotle gave above. Here's a CGI snippet that shows a way to handle the field/error reporting without naming them with variables at all.

      The logic of the sample is not good for a real CGI but the technique itself works great and I get to show the serial comma function again. :)

      #!/usr/bin/perl #========================================================= use warnings; use strict; use CGI qw(:standard); #========================================================= print header(), start_html(), start_form(); my @param_names = qw( title address description ); my @missing = grep { not param($_) } @param_names; if ( param('submitted') and @missing ) { print "Please fill in: ", i({-style=>'color:#A00;'}, serial(@missing) . '.' ); } for my $field ( @param_names ) { print p( b($field), textfield(-name => $field ) ); } print submit(-name=>'submitted'); print end_form(), end_html(); exit 0; #========================================================= sub serial { join(', ', @_[0..$#_-1]) . (@_>2 ? ',':'' ) . (@_>1 ? (' and ' . $_[-1]) : $_[-1]); }
    Re: Constant variables
    by Anonymous Monk on Apr 28, 2003 at 09:36 UTC
      Define it outside the unless loops as (maybe) my $errorcount = 0;