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

Hello, monks,

I'm working on a web application that is getting bigger and bigger all the time. I'm running it on Apache web server. I have the -w switch turned on. However, my Apache error.log file is filled with hundreds of messages of this sort: Use of uninitialized value in concatenation (.) or string etc This means that some of my variables are undef ined when I'm using them. To avoid these warnings I'd have to set if(defined($something)) statements in my code. But I don't want to make my code more complicated to read. So the question is: what is best to choose, turn off the -w option, do variable check in the code, divide/structure the code or is there another way of doing this? How to find a balance between strictness and over-complication of the code?

Thank you.

Replies are listed 'Best First'.
Re: The -w switch on a web application
by helgi (Hermit) on Jan 31, 2003 at 08:54 UTC
    This is a very common problem. I agree with aragorn that it is far better to correct this at the source rather than fix the symptoms. I can't see your code, so my recommendations have to be rather generic.

    First, debug from the command line, not through the CGI interface.

    Second, stick in some warnings before doing any string concatenations or interpolations, i.e. something like:

    if (not $variable) { warn "\$variable is uninitialized\n"; }
    This should help you isolate which variables are empty.

    Why are they empty? One common reason is that you have forgotten about empty lines in the input data. I like next if /^\s+$/; to deal with those common cases.

    Also, I think you should leave strictures, warnings and taint checking ON even in production code. If it is properly written, it should not generate warnings.

    --
    Regards,
    Helgi Briem
    helgi AT decode DOT is

      You'll want to say unless (defined $variable) { warn "\$variable is uninitialized\n"; } because there are false values that are still defined.


      Seeking Green geeks in Minnesota

Re: The -w switch on a web application
by Aragorn (Curate) on Jan 31, 2003 at 08:41 UTC
    In my opionion, it would be wise to find out why these variables aren't initialized. Altough I like the "fail-soft" characteristics of Perl when I write a one-liner or one-off script, things that talk to the big bad outside world should be robust.

    Using if (defined($something)) statements is trying to get rid of the symptoms. Instead, make sure that each variable you use is properly initialized. This will make your code much more robust and resilient against probable attacks. For Web-stuff, I think it's wise to not only use strict and warnings, but also the -T (taint checking) command-line option.

Re: The -w switch on a web application
by Tanalis (Curate) on Jan 31, 2003 at 08:22 UTC
    Personally, I tend to code with -w when I'm developing and testing an application. Once that's done, I rarely leave the warnings turned on when the code is released to production.

    I understand that the warnings can be useful to have for debugging reasons if (when) things go wrong, especially to pick up run-time errors. I do think, though, that that small(ish) bonus is soon cancelled out when you consider the chore of digging through logs, especially with a large, oft-used application (like a website).

    As long as you're aware of why the warning is appearing at design-time, it seems fairly pointless to keep having that warning appear, and get logged, in production.

    I see warnings as a very useful debugging tool, rather than something to directly test the correctness of my code - after all, that's what use strict and the compiler are for *grins*. Warnings at best, in my mind, drop hints as to why things are going wrong, not what is wrong.

    -- Foxcub
    A friend is someone who can see straight through you, yet still enjoy the view. (Anon)

      Testing with defined is much the same as deleting the -w. The var is still not defined; you are just living with it. Is it possible that a cgi using the -w and working fine may fall over at a later date if prel or a module that is used is upgraded or altered in some way?
Re: The -w switch on a web application
by Ryszard (Priest) on Jan 31, 2003 at 08:23 UTC
    IMHO, I want to know specifically what data is going thru' my application. If there are undef values, they should be handled. its all part of making a tight application.

    It is also handy to specifically handle the undef cases as you may turn up bugs in your application, you didnt realise were there...

    Update: you should _always_ be using your -T switch also and throwing away naughty chars (including but not limited to); ' " | when appropriate.

Re: The -w switch on a web application
by PodMaster (Abbot) on Jan 31, 2003 at 08:27 UTC
    I think it's a good idea to use defined ... however, if you got a new enough perl (and you should), look into the warnings pragma.
    use warnings; no warnings 'uninitialized';
    The other benefit of the "warnings" pragma is that its properly scoped, where as -w(aka $^W) is global, after all, you only wanna get warnings generated by your code, unless you plan submitting patches ;)


    MJD says you can't just make shit up and expect the computer to know what you mean, retardo!
    ** The Third rule of perl club is a statement of fact: pod is sexy.

      and if you have older perl...

      #!/usr/bin/perl -w $SIG{__WARN__} = sub { local $_ = shift; print STDERR unless /Use of uninitialized value/; }; my $f; print "no warning here -->$f<--",$/; warn "woot! other warnings here...";
Re: The -w switch on a web application
by CountZero (Bishop) on Jan 31, 2003 at 11:00 UTC

    And of course if your scripts are running under Apache mod_perl, if you are not careful in initializing your variables (or using my whenever possible) you may "carry over" values from a previous run of your script as mod_perl does not recompile your scripts for every request.

    CountZero

    "If you have four groups working on a compiler, you'll get a 4-pass compiler." - Conway's Law

Re: The -w switch on a web application
by physi (Friar) on Jan 31, 2003 at 08:26 UTC
    IMHO I would try to get the 'unreadable' solution running ;-) This is more unhandy to read, but on the other hand, you can find 'real-errors' in your access.log easier.
    And it will give you more information, when you have to integrate a 'hot-fix' on the Life-System ;-)
    Btw. Try use warnings instead of -w.
    ----------------------------------- --the good, the bad and the physi-- -----------------------------------
Re: The -w switch on a web application
by Heidegger (Hermit) on Jan 31, 2003 at 13:04 UTC

    Below I posted two pieces of the code. The first one is checking for defines, the second - doesn't. The second one is more nicer, because if we don't check for undef values, we can delegate function calls to each other without having intermediate variables. If I start checking for defines, my code becomes full of if and unless sentences.

    The code is creating a menu object and setting the active menu for it, which it has to display say in a different color. Of course, the checking for the active menu could be done inside the Menu object, but in my design it's outside. So, my code has to check for the undef value from the CGI param() function and from my get_active_menu_id() functions as well, because they don't always return a defined value.

    I lose the flexibility of perl and I worry pretty much about it. What should you do in such a situation?

    The checks for defined version:

    my $main_menu = new Menu("main"); my $menu_item = param('menu_item'); if(defined($menu_item)) { my $active_menu_id = get_active_menu($menu_item); $main_menu->active_menu_id($active_menu_id) unless !$active_menu_id; } $main_menu->output;

    No checks for defined version:

    my $main_menu = new Menu("main"); $main_menu->active_menu_id(get_active_menu(param('menu_item'))); $main_menu->output;

    So what do you think, is it worth checking for defines on such a code or not?

      Depends on which of these is realistically going to make a difference. I'd write something like this:
      my $main_menu = Menu->new("main"); my $active_menu_id = get_active_menu(param('menu_item')||''); $main_menu->active_menu_id($active_menu_id) if defined $active_menu_id; $main_menu->output;

      The distinction between the user selecting no menu item or submitting an invalid selection is not likely to matter, so I just default that case to a defined but invalid value. Whether or not he has select a valid menu item however definitely is important, so I check that case appropriately.

      Btw, indirect object syntax looks neat but has a bunch of caveats. Use the arrow notation instead.

      Makeshifts last the longest.

      And this is part of where perl6 will be very nice. It is an important thing though to provide default values especially for web programming since if you port to mod_perl then you are required to provide default values regardless.

      # Provide an empty string as the default value if the # menu item value isn't provided. my $menu_item = param('menu_item') // '';

      In perl5 I write this as:

      # Provide an empty string as the default value if the # menu item value isn't provided. my $menu_item = param('menu_item'); $menu_item = '' unless defined $menu_item; # OR to be brief local $_; # As you enter the block $_ = param('menu_item'); my $menu_item = defined() ? $_ : '';

      Or if you feel like being cute (and slightly obfuscatory)

      $menu_item = defined() ? $_ : '' for (param('menu_item');

      I think you also meant to write unless ! as if but that's separate.


      Seeking Green geeks in Minnesota

      Test, test, test. Yes the second snippet is straight forward, but im sure there would be all sorts of ways to mess with it. How about something like the following..
      # # I split the code, but I dont think it would need to be on # a new line in an 80 char window # my $main_menu = new Menu("main") || &some_error_routine("Failed to create menu obj! $main_menu->err\ +n"); my $menu_item = param('menu_item') || &some_error_routine("No menu_item passed to cgi!"); my $active_menu_id = get_active_menu($menu_item) || &some_error_routine("Cant collect menu_id!!\n"); # # There should probably be a test here as well # $main_menu->active_menu_id($active_menu_id); $main_menu->output;
      If the sub routines return 0, nothing, or undef the second half of a line will be executed. Also when attempting to debug later, you can do a couple of things. Within the some_error_routine, you can watch for say a global $DEBUG, and depending on what the value of it is, you can determine what types of messages to send out to the log file, if debug isnt defined and you receive messages to be logged, you can still trim down your output, but you dont need to spend X amount of time adding debug statements to the rest of your code. You simply go to main, define 1 scalar, and then run the code again. Once your done with testing, you whack the scalar and everything goes back to normal.

      I find it best for myself, that once a app reaches a certain point in either complexity or frequence of run time, I add a simple error logging sub. But hey its just works for me :)

      Edit: Post morning coffee, I realize I didn't really stress what I wanted to. Basically you can control the behaviour of your code in terms of logging and dieing from a single sub. Also with logging this way, and parsing the error log, you should be able to quickly figure out where in the code you failed and for what reason. You could get this done via croak/warn/die, but if the app is getting as big as you say, its easier for me to control it all from a single point, as opposed to multiple source files and libs.

      /* And the Creator, against his better judgement, wrote man.c */
Re: The -w switch on a web application
by december (Pilgrim) on Jan 31, 2003 at 11:09 UTC

    I put them on for coding on intranet, but off when uploading to a 'real' webserver. It's indeed quite annoying having your logs filled with things like 'undefined variable' (e.g. from templates). I sync my real webserver with the intranet webserver tree (ssh dsa key), rewriting some files to get rid of debugging parameters automatically.

    You could do fake initialisations to fool perl, too.

    Either way, don't let it stop you from using things like 'strict' and 'tainted data' when coding.

Re: The -w switch on a web application
by kiz (Monk) on Jan 31, 2003 at 11:52 UTC
    I could be on the wrong track here, however are you defining variables before you use them? The line:
    print "The string is $foo\n";
    may give you an "uninitialised value, as $foo may not be defined yet. whereas:
    my $foo; # some code print "The string is $foo\n";
    should be better - as $foo has been defined.. Referencing into hashes, only to discover that the particular key you're trying to use does not exists is another area that results in a very similar problem :)

    -- Ian Stuart
    A man depriving some poor village, somewhere, of a first-class idiot.

      I think you're slightly confused about what these error messages mean. If you don't declare a variable, you'll get the "requires explicit package name" error. This is triggered by use strict, not by -w.

      $ perl -Mstrict -le 'print $x' Global symbol "$x" requires explicit package name at -e line 1. Execution of -e aborted due to compilation errors.

      The error we're dicsussing here is seen whenever you try to print a variable that contains "undef" (even if it's previously been declared). This is triggered by -w (or use warnings).

      $ perl -Mstrict -w -le 'print my $x' Use of uninitialized value in print at -e line 1.
      --
      <http://www.dave.org.uk>

      "The first rule of Perl club is you do not talk about Perl club."
      -- Chip Salzenberg