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

Hi monks, how do you do?

I have one little newbie question here. I don't quite get this. I get a "Use of uninitialized value in substraction (-)" warning on this code:
sub queryDBI { my $query1 = "SELECT $_[2],$_[3],$_[$_-1] FROM ".$_[1];
I know the code is pointless right now I'm just doing some tests with DBI code. Well, the problem is the [$_-1] part.
I tried several different ways of getting rid of that but nothing works.Care to explain please?
Thanks in advance.

Replies are listed 'Best First'.
Re: Uninitialized value warning in subrutine
by brian_d_foy (Abbot) on Jan 29, 2005 at 03:11 UTC

    Print each of the values before you do anything, and see which one doesn't have a value. Figure out why that variable doesn't have a value and you'll figure out how to get rid of that warning.

    What is the $_[$_-1] supposed to do? Do you really mean to use a global variable, $_, like that?

    --
    brian d foy <bdfoy@cpan.org>
Re: Uninitialized value warning in subrutine
by demerphq (Chancellor) on Jan 29, 2005 at 09:37 UTC

    Just a minor style comment, this style of argument handling is a little bit unusual. Generally this would look like:

    sub queryDBI { my ($foo,$bar,$baz,$table)=@_; my $query="Select $foo, $bar, $baz from $table";

    Directly accessing @_ is ugly and confusing and suffers from the problem that if you change the order of arguments or perhaps add a new argument somewhere in the middle making the appropriate changes is quite error prone. People occasionally do it in "tiny subs" and gurus will occasionally resort to it for their own purposes (remember @_ is magic) but to see it in code like this is a bad sign. Use named lexical copies of the arguments instead.

    ---
    demerphq

Re: Uninitialized value warning in subrutine
by jimrobertsiii (Scribe) on Jan 29, 2005 at 04:39 UTC
    Presumebly you have turned on warnings which is a great start! Otherwise you would not have noticed this issue at all.

    One thing that helps me out tremendously (other then -w) when trying to test how things work is to use the debugger. Not sure exactly where I picked this up, but to use the debugger interactively without firing up a script do the following:

    perl -d -e 0

    This will give you a prompt that you can use to execute a line of perl. This is priceless when trying to figure out how perl is really working.

    In this case, pasting $query1 = "SELECT $_[2],$_[3],$_[$_-1] FROM ".$_[1] into the prompt produces tons of uninitialized variable warnings for $_. The next thing I would do would be to test (some what visually) if in fact $_ was actually defined (from the warning there is no way that it could be, but "trust, but verify"). To do this simply print defined $_. If $_ were initialized the print statement would print a 1, but since it is not it prints nothing (a blank line is printed).

    There are some caveats about scoping (my variables) and you will want to check out the "x $hash_ref" command if you use a lot of hash references.

    -Jim

Re: Uninitialized value warning in subrutine
by olivierp (Hermit) on Jan 29, 2005 at 09:18 UTC
    I assume you would like to access the last element of the implicit @_ array. Note that @_ and $_ are 2 different variables, as @var and $var are.
    In a sub, @_ represents the arguments that you passed in, and this is what you should be accessing, whereas $_ is the "default" variable used/created in various looping constructs, the "default" match target , amongst others, as infor (@array){ print $_ if /hello world/i}
    Your "Use of uninitialized value in substraction (-)" comes from trying to substract 1 from the $_ variable, which is undefined in the sub, when you actually would like to substract 1 from the number of items in @_
    Here are 3 ways of achieving what you are looking for:
    # Access directly the last element of the array sub queryDBI { my $query1 = "SELECT $_[2],$_[3],$_[-1] FROM " . $_[1]; return $query1; } print queryDBI(qw/first second third fourth fifth_and_last/),$/ x 2'
    # In scalar context, @array returns the number of elements in contains +. # As @array indexes start at 0 (unless someone explicitly changes this + through $[), we substract 1 sub queryDBI { my $query1 = "SELECT $_[2],$_[3],$_[@_-1] FROM " . $_[1]; return $query1; } print queryDBI(qw/first second third fourth fifth_and_last/),$/ x 2'
    # $#array returns the index of the last element of the array. sub queryDBI { my $query1 = "SELECT $_[2],$_[3],$_[$#_] FROM " . $_[1]; return $query1; } print queryDBI(qw/first second third fourth fifth_and_last/),$/ x 2'
    For further info on predefined variables, as $_ and @_ check out perlvar
    HTH
    --
    Olivier
Re: Uninitialized value warning in subrutine
by dave_the_m (Monsignor) on Jan 29, 2005 at 02:17 UTC
    Presumably at the point that queryDBI is called, $_ happens not to have a defined value.

    Dave.