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

Edit: Solution found, thank you ikegami!

I am having consistent issues with an "uninitialized" value warning in my script, and I can't seem to identify the problem:

package EcomAllcancel; use warnings; use strict; use lib "./feedmodules"; use EcomImportUtilities; sub execute { my $biuw = shift; my $TABLE = 'ecom_allcancel'; my $FILE = 'cmdaycan.data'; my $PATH = "$biuw->{yml}{filepath}/orderinfo/"; my $table_summary = $TABLE . '_summary'; my $DATE_COLUMN = 'date_cancel'; my $ALLOWED_CHANGE = $biuw->{yml}{allcancel_allowed_change}; my $temp_table = $TABLE . '_temp'; my $feedfullpath = $PATH . $FILE; $biuw->{log}->info("\n\n**********\nBegin $TABLE load sequence\n** +********\n\n"); my $exception = EcomImportUtilities::ageCheck( biuw => $biuw, feedpath => $feedfullpath, tablename => $TABLE ) unless $biuw->{const}{load_old}; if ($exception->{exception} eq 'outofdate' or $exception->{excepti +on} eq 'stillcopying') { $biuw->{log}->warn("$feedfullpath is out of date. Loading stop +ped.\n"); return $exception; } elsif ($exception->{exception} eq 'nonexistent') { $biuw->{log}->warn("$feedfullpath does not exist. Loading stop +ped.\n"); return $exception; }

This is simply the beginning of the code. The $exception hash is loaded into a subroutine on another module, which will return a hash that looks like this:

my $exception = { table => $tablename, exception => 'nonexistent', data => { file => $filepath, age => 0, nonexistent => 1 } }; return ($exception); }

I keep getting errors stating that there is "Use of uninitialized value in string eq" at line 34, 34 and 39. From what I can gather, it is referring to the "$exception->{exception}" references, but I can't seem to figure out why this is causing the issue. I declared the $exception, and the $exception->{exception} is declared in the subroutine module. Why would it still be coming back as "uninitialized"?

So far I have tried simply adding a line to the hash (exception => '' / exception => undef) or declare it separately (my $exception{exception};) but the warning persists. I am clearly overlooking something that should be obvious, but I can't figure this one out.

Replies are listed 'Best First'.
Re: Initialized Variable getting Uninitialized Warning
by ikegami (Patriarch) on Feb 27, 2019 at 17:51 UTC

    Never execute a my conditionally, and use then use declared variable under wider conditions. my $var = ... unless ...; ... $var ... is undefined behaviour.

    Fix:

    if (!$biuw->{const}{load_old}) { if ( my $exception = EcomImportUtilities::ageCheck( biuw => $biuw, feedpath => $feedfullpath, tablename => $TABLE ) ) { if ($exception->{exception} eq 'outofdate' || $exception->{exception} eq 'stillcopying ) { $biuw->{log}->warn( "$feedfullpath is out of date. " . "Loading stopped.\n"); return $exception; } elsif ($exception->{exception} eq 'nonexistent') { $biuw->{log}->warn( "$feedfullpath does not exist. " . "Loading stopped.\n"); return $exception; } } }

      Thank you for the response, though I am a little confused by the solution.

      The $exception needs to be run through the EcomImportUtilities::ageCheck when the program is run, and only not when the "load old" argument is set. Why would I want that to be nested in an "if" statement? My understanding is by declaring $exception = EcomImportUtilities::ageCheck, it actually runs the subroutine. Am I mistaken? Maybe something like this instead:

      unless ($biuw->{const}{load_old}) { my $exception = EcomImportUtilities::ageCheck( biuw => $biuw, feedpath => $feedfullpath, tablename => $TABLE ) if ($exception->{exception} eq 'outofdate' || $exception->{exception} eq 'stillcopying ) { $biuw->{log}->warn( "$feedfullpath is out of date. " . "Loading stopped.\n"); return $exception; } elsif ($exception->{exception} eq 'nonexistent') { $biuw->{log}->warn( "$feedfullpath does not exist. " . "Loading stopped.\n"); return $exception; } }

      I think I understand why I am getting the undefined warning now, and I appreciate your help.

        Sure, if ageCheck always returns an exception. But then it wouldn't be an exception, would it? So either add the necessary if, or rename the variable to something that makes more sense (such as "result").

        (As for the line breaks, I added them so the code looks better on PerlMonks. There's no reason to keep them.)

Re: Initialized Variable getting Uninitialized Warning
by ikegami (Patriarch) on Feb 27, 2019 at 17:46 UTC

    "Uninitialized" really means "has undef for value". Adding if (defined($exception->{exception})) { } or even just if ($exception->{exception}) { } will address the issue.

      But the value wouldn't be defined until it runs through the secondary module. I've tried simply stating:

      my $exception = EcomImportUtilities::ageCheck( ... ... ... exception => undef

      but that seems to have no affect on the warnings.

        exception => undef

        ikegami pointed out the likely culprit. But if you hadn't seen that, then what you just said is the opposite of what I would do after reading >>"Uninitialized" really means "has undef for value"<< in ikegami's first post. My recommendation would have been to figure out why the exception-key's value was being set to undef, not intentionally force it to undef.

        To do that here, I would have made a print statement (This is step#2 from Basic debugging checklist)

        printf STDERR "ref=%s, exception->{exception}=%s\n", $exception, $exception->{exception}//'<undef>';

        ... and placed it right before the return($exception) in your subroutine and just after the my $exception = EcomImportUtilities::ageCheck(...). This would have shown you that it was properly defined in the sub, but the hashref wasn't getting into the local $my exception at all, which would have pointed you toward ikegami's conclusion that the conditional-my was what was messing with you -- or, at least, you could have asked "why is $exception a proper hashref in the sub, and not after the subroutine-call?", at which point, ikegami would have chimed in.

        Hope this helps you for future debugging


        (edit: move the step#2 comment to subsequent paragraph, where it fits better)