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

Fellow Monks, I recently ran into a seemingly simple problem, which to my complete surprise managed to stumped me.
Scenario:
for my $row (@{$dates}) { $seasons{'low'} = $row->[0] if ($row->[0] < $seasons{'low'}); $seasons{'high'} = $row->[1] if ($row->[1] > $seasons{'high'}); }
At some point the vars $row->[0] and $row->[1] were empty, this eventually broke a few other parts of the code which depended on this information. What I was wanting to do is act on the variables if the $row vars were empty, rather than checking for a value I assumed I could act if $! had a value.
for my $row (@{$dates}) { $seasons{'low'} = $row->[0] if ($row->[0] < $seasons{'low'}); print "$row->[2]\n" if $!; $seasons{'high'} = $row->[1] if ($row->[1] > $seasons{'high'}); }
The theory behind it was that if an uninitialized var was being used a warning would pop up and I would print the corresponding id to let me know if it was empty.

I was trying to save myself a little bit of work by not testing the variable for a value. Of course my thoughts on how to do this were wrong since $! never had any value. I've scoured 'perldoc warnings & perlvar & perllexwarn ' to no avail, I am aware that I could use an eval to wrap the code in, but this is the innermost loop of a resource hungry piece of code and I was trying to avoid taking as many extra steps as possible to gain the advantage of speed.

Please note that this is not production code and the value of $row->[2] obtained by testing would be used via another method to populate $row

Any thoughts?

BlackJudas

Replies are listed 'Best First'.
Re: Trapping a warning
by chromatic (Archbishop) on Jul 03, 2002 at 22:04 UTC

    Don't work so hard.

    warn "Empty row ($row->[2])\n" unless defined $row->[0];
Re: Trapping a warning
by zaimoni (Beadle) on Jul 03, 2002 at 22:40 UTC

    Welcome to autovivification. I've fried myself quite a few times on this as well.

    Even if those reference-array entries $row->[0] and $row->[1] didn't exist before with your original code, they do exist (and are undef) after that code runs. The subsequent code is not likely to appreciate this.

    To test whether $row->[0] and $row->[1] are defined without risking autovivification, use something like

    if (defined($row) and defined($row->[0]) and defined($row->[1]) { # .... }

    The first clause tests for whether the $row variable is defined. If that variable is defined, we proceed to test whether the 0 and 1 entries of the referenced array are defined. This also prevents being flummoxed by 0 (which is Perl-false).

    Of course, do this before you start using $row->[0] and $row->[1]. After that, it's too late.

      Well, if you want to check whether $row->[0] and $row->[1] exists without autovivification, just check whether $row contains any elements. $row->[0] can only exist if and only if @$row > 0. Similar, $row -> [1] only exists if and only if @$row > 1.

      Note that from 5.6.0 onwards, delete and exists work on arrays as well.

      Abigail

Re: Trapping a warning
by Jim Morrison (Novice) on Jul 03, 2002 at 21:55 UTC
    perlfaq7.pod has a very related advice:
    =head2 How can I catch accesses to undefined variables/functions/metho +ds? The AUTOLOAD method, discussed in L<perlsub/"Autoloading"> and L<perltoot/"AUTOLOAD: Proxy Methods">, lets you capture calls to undefined functions and methods. When it comes to undefined variables that would trigger a warning under C<-w>, you can use a handler to trap the pseudo-signal C<__WARN__> like this: $SIG{__WARN__} = sub { for ( $_[0] ) { # voici un switch statement /Use of uninitialized value/ && do { # promote warning to a fatal die $_; }; # other warning cases to catch could go here; warn $_; } };

    Adopt that code, and you will be able to "intercept" your warnings and use a value of "$!" at your will
    Also, do not forget to protect your code by

    try { } if ($@) { ... }
    Jim
Re: Trapping a warning
by blackjudas (Pilgrim) on Jul 04, 2002 at 17:49 UTC
    Thank you all for your input, I don't think I've fully explained my question. I know about autovivification and testing for truth on a variable, but in this case I was looking for a solution to use Perl's built-in warnings and how I would test for that situation.

    BlackJudas