Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

-w in production environment

by gwhite (Friar)
on Jul 05, 2001 at 22:47 UTC ( [id://94197]=perlquestion: print w/replies, xml ) Need Help??

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

I have a Perl CGI program that I am placing the finishing touches on, during debugging I have kept -w and use strict; in the appropriate places.

My input is an HTML form with 100 or more inputs. Which I drop into a hash (%USER) to process. Some of the questions will be left blank or answered with an answer of 0. This causes some of the variables to show as uninitialized in some warning messages. An example of the code that causes this error would be:

if ($USER{coffee} > 5){$msg='You drink too much coffee'}

If $USER{coffee} is left blank or 0 is the response I get a message that says "Use of uninitialized value in numeric gt (>) at .....". OK, I know why that happens, but it seems inappropriate to write the code like:

if ($USER{coffee}){if ($USER{coffee} > 5){$msg='You drink too much coffee'}}

just to eliminate the error message. But my clients are not going to be thrilled with a lot of warning messages like this piling up in the error logs. Since I have run over 10,000 sample data sets through, should I just eliminate the -w for the production code, or have I missed something much more obvious and elegant.

And does use strict; increase the time to load and process the code, which in a production environment after rigorous testing can be eliminated.

Thanks,
Greg

Replies are listed 'Best First'.
Re: -w in production environment
by tachyon (Chancellor) on Jul 05, 2001 at 23:21 UTC

    Eliminating -w is one option that will work and is reasonable if you have completely debugged all the code...If you find a reliable method please tell me how! Another option is to initialise all your values. It depends on how your script is structured as to how you do this. Say you are using CGI.pm, here is what you usually find at the top of my scripts:

    #!/usr/bin/perl -wT use strict; use CGI; my $q = new CGI; my $var = $q->param('var') || ''; untaint(\$var); # warning do not do this my @ary = $q->param('options') || (); # this kills the array return of CGI.pm

    If you use param queries directly you can do this to define all undefined values:

    my @fields = qw(foo bar baz); for (@fields) { $q->param($_,'') unless defined $q->param($_); }

    This iterates over the field names an pushes a null string into the value if it is not defined. You can use the same method for a hash:

    my @fields = qw (foo bar baz); for (@fields) { $USER{$_} = '' unless defined $USER{$_}; }

    Use strict does have an overhead (a very small overhead) - try benchmarking if you are really worried and execution speed is everything. Use mod perl in this case! The reason for leaving use strict and -w active is that your code *will* be modified one day, perhaps by you, perhaps not. If they are active no one has to to remember to reactivate them. If you must kill them comment them out rather than erase them entirely with a note that the should be used for testing modifications to the code.

    cheers

    tachyon

    s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

      Use strict does have an overhead

      ?? Well, that is pretty darn misleading. use strict has a very, very tiny overhead such that most people that I respect and who I've heard weigh in on the subject feel that the work of adding and removing strict between testing and production (and more importantly, the risk of forgetting to add it back in each time changes are made) outweigh the cost by a wide margin.

      Taint checking is also something that should not be disabled in production (even more so than strict).

      Warnings, however, are much easier to justify removing from production. Perhaps the best situation would be to keep warnings enabled but have a separate infrastructure for collecting warnings information and making sure the volume of information can't become a burden.

      But if you don't create a separate infrastructure for warnings, I'd definitely turn them off in production.

              - tye (but my friends call me "Tye")

        Hi, it's not misleading at all. *Every* operation in Perl has an overhead - including use strict. As the question was "does use strict have an overhead?" the answer is/was correct. I then went on to suggest benchmarking and mod Perl if speed was the critical issue and then additionally suggest reasons not to disable use strict and -w....as you reiterated....

        cheers

        tachyon

        s&&rsenoyhcatreve&&&s&n.+t&"$'$`$\"$\&"&ee&&y&srve&&d&&print

Re: -w in production environment
by Abigail (Deacon) on Jul 06, 2001 at 02:45 UTC
    I agree with people that you should keep -w in production code. Sure, it does mean you might have to add some more code where you otherwise could get away with cutting corners. But if later the customer comes with "it doesn't work", and you have nothing else to fall back on (nothing in the error logs), it might be hard to fix the problem, while it would have been trivial if you had the warning(s).

    I am however surprised about the suggested "fixes" several of the previous posters gave. Just checking whether $USER {coffee} exists or is defined fixes all possible warnings! Sure, it avoids the use of uninitialized value warning, but clearly, the form input hasn't been checked for sanity! What if $USER {coffee} contains Java? Argument "java" isn't numeric in numeric gt isn't much better as warning message.

    You cannot trust form input. Don't assume it's there, and don't assume it's in the format you want it to be. Don't assume it's a number just because you are going to use it as a number.

    -- Abigail

Re: -w in production environment
by chromatic (Archbishop) on Jul 06, 2001 at 01:59 UTC
    One other option is to add your own warn handler that ignores uninitialized value warnings. Personally, I'd rather deal with them in the code so as to avoid nasty surprises, but it can come in handy sometimes:
    $SIG{__WARN__} = sub { unless ($_[0] =~ /^Use of uninitialized value/) { warn $_[0]; } };
    Looks like there's more information in warn and perlvar.
Re: -w in production environment
by clintp (Curate) on Jul 05, 2001 at 23:27 UTC
    Regardless of whether or not you're using CGI.pm (that's none of my business) you should leave the warnings on anyway. It's going to catch other problems eventually and that's a Good Thing.

    Lots of gratuitous errors in the log will cause people to ignore the log...So...

    If you honestly expect a lot of blank fields, and the prospect of checking for defined-and-then-a-value makes you nauseous, just pre-cook them all with a defined value (like the empty string) before you use them:

    for(keys %USER) { $USER{$_}="" unless defined $USER{$_}; }
Re: -w in production environment
by clscott (Friar) on Jul 05, 2001 at 23:52 UTC
    You actually want this:
    if (exists $USER{coffee} && $USER{coffee} > 5){$msg='You drink too muc +h coffee'}

    It checks that the coffee key exists in %USER. You can just use

    if ($USER{coffee} && $USER{coffee} > 5){$msg='You drink too much coffe +e'}
    It will get rid of the warning, but won't actually do anything useful. exists checks that the coffee key was created. This check actually tells you a potentially relevant piece of information. e.g
    if (! exists $USER{coffee}){ $msg = 'You drank no coffee?!?!'; } elsif ($USER{coffee} > 5){ $msg='You drink too much coffee'; } else { $msg='You drank a moderate amount of coffee'; }
    There is no point in adding code just to get rid of a warning if the new code does nothing useful! It is a poor practice to get into and can be confusing to the people that have to maintain you application. Like Abigail said check your input to make sure no one made a mistake inputting a value (or is pulling a fast one on you).

    This doesn't seem to be the behaviour that you want.

    HTH,
    Clayton

    Update:
    I removed a section that said testing if a non exsistant key was defined would autovivify it and added my support for Abigail's answer. I swear with God as my witness...

      If you used defined $USER{coffee} as a check it will actually autovivify (automatically create) the coffee key as it does when you do your current test.

      That's not true:

      use warnings; use strict; my %c = ( hey=>'Joe', where=>'you goin\'', with=>'that gun in your hand'); if (defined $c{Hendrix}) { print "Jimi is alive and well\n"; } foreach ( sort keys %c ) { print "Key : $_ => $c{$_}\n"; }

      This does not print "Hendrix" and yield up a warning on the loop that goes through the keys (Perl 5.6.1, Win32).

      Of course defined $hash{key} and exists $hash{key} do test for different things:

      $hash{key} = undef; #defined $hash{key} false, exists $hash{key} true
      perl -e 'print "How sweet does a rose smell? "; chomp ($n = <STDIN>); +$rose = "smells sweet to degree $n"; *other_name = *rose; print "$oth +er_name\n"'
Re: -w in production environment
by converter (Priest) on Jul 05, 2001 at 23:12 UTC

    You didn't mention if you were using CGI.pm or not, but I'll assume that you are since most good Perl programmers use it. :)

    &CGI::param should returned the undefined value only for those fields left blank by the user, a value of zero is not undefined, so I doubt fields filled with zero are causing a warning. To accomodate possible empty fields, check the value returned by param() and if it is not defined, assign an empty string or zero, whichever is appropriate. Something like:

    $USER{coffee} = param('coffee') || 0;
Re: -w in production environment
by epoptai (Curate) on Jul 05, 2001 at 23:56 UTC
    In addition to all the good answers already given:

    You don't need two if statements. This is simpler:

    if ($USER{coffee} && $USER{coffee} > 5){ $msg = 'You drink too much coffee' }
    It's still redundant, but that's part of the point of using warnings. Warnings seem to make perl assume less about what you mean, so you need to tell it more about what you want. In my experience strict and warnings compliant code is always larger and slower than 'casual' freestyle perl code, but for large scripts the price is well worth what it buys in security and stability.

    Update: Abigail makes a good point about sanity checking. For that perl needs more information about what we expect our input to contain:
    if ($USER{coffee} && $USER{coffee} =~ /\d+/){ $msg = 'You drink too much coffee' if $USER{coffee} > 5; }

    --
    Check out my Perlmonks Related Scripts like framechat, reputer, and xNN.

Re: -w in production environment
by scain (Curate) on Jul 05, 2001 at 22:53 UTC
    I don't see why a response of 0 would give an uninitialized warning. Are you sure it does? I was going to suggest putting default responses in the html form to eliminate the warnings, but if you are getting the response in the way you indicate, default responses may not fix it.

    Scott

      I'm not sure if this is browser dependant or not, but upon posting a html form with a zero value, I have found many times that the element is not passed through to the script.

      I am using CGI.pm

      Greg

Re: -w in production environment
by Zaxo (Archbishop) on Jul 05, 2001 at 23:00 UTC

    Sorry, but I think those warnings are telling you you haven't finished the job. You're still debugging, so that's ok.

    Obligatory Question: you are using CGI.pm, aren't you?

    After Compline,
    Zaxo

Re: -w in production environment
by blakem (Monsignor) on Jul 05, 2001 at 23:03 UTC
    I believe use strict catches mostly compile-time errors, and it does take time to run (and pull in the extra code.) If you are really pining for those extra few miliseconds, its probably "safe" to remove it from production code. However, i've found it to be more of a hassle than its worth..... I usually prefer to just leave the use strict in the production code.

    -Blake

Re: -w in production environment
by Anonymous Monk on Jul 05, 2001 at 23:28 UTC
    I'm not sure if this is a solution you will want to use but here is what I usually do. Instead of
    if ($USER{coffee} > 5){ ... }
    I would use
    if (defined($USER{coffee}) && $USER{coffee} > 5) { ... }
    I feel checking defindedness is good thing to do in any case.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (6)
As of 2024-03-29 00:09 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found